Ajout du FR
Ajout du FR + correction du "functions.php"
This commit is contained in:
480
phpbb/attachment/delete.php
Normal file
480
phpbb/attachment/delete.php
Normal file
@@ -0,0 +1,480 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\attachment;
|
||||
|
||||
use \phpbb\config\config;
|
||||
use \phpbb\db\driver\driver_interface;
|
||||
use \phpbb\event\dispatcher;
|
||||
use \phpbb\filesystem\filesystem;
|
||||
|
||||
/**
|
||||
* Attachment delete class
|
||||
*/
|
||||
class delete
|
||||
{
|
||||
/** @var config */
|
||||
protected $config;
|
||||
|
||||
/** @var driver_interface */
|
||||
protected $db;
|
||||
|
||||
/** @var dispatcher */
|
||||
protected $dispatcher;
|
||||
|
||||
/** @var filesystem */
|
||||
protected $filesystem;
|
||||
|
||||
/** @var resync */
|
||||
protected $resync;
|
||||
|
||||
/** @var string phpBB root path */
|
||||
protected $phpbb_root_path;
|
||||
|
||||
/** @var array Attachement IDs */
|
||||
protected $ids;
|
||||
|
||||
/** @var string SQL ID string */
|
||||
private $sql_id;
|
||||
|
||||
/** @var string SQL where string */
|
||||
private $sql_where = '';
|
||||
|
||||
/** @var int Number of deleted items */
|
||||
private $num_deleted;
|
||||
|
||||
/** @var array Post IDs */
|
||||
private $post_ids = array();
|
||||
|
||||
/** @var array Message IDs */
|
||||
private $message_ids = array();
|
||||
|
||||
/** @var array Topic IDs */
|
||||
private $topic_ids = array();
|
||||
|
||||
/** @var array Info of physical file */
|
||||
private $physical = array();
|
||||
|
||||
/**
|
||||
* Attachment delete class constructor
|
||||
*
|
||||
* @param config $config
|
||||
* @param driver_interface $db
|
||||
* @param dispatcher $dispatcher
|
||||
* @param filesystem $filesystem
|
||||
* @param resync $resync
|
||||
* @param string $phpbb_root_path
|
||||
*/
|
||||
public function __construct(config $config, driver_interface $db, dispatcher $dispatcher, filesystem $filesystem, resync $resync, $phpbb_root_path)
|
||||
{
|
||||
$this->config = $config;
|
||||
$this->db = $db;
|
||||
$this->dispatcher = $dispatcher;
|
||||
$this->filesystem = $filesystem;
|
||||
$this->resync = $resync;
|
||||
$this->phpbb_root_path = $phpbb_root_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete Attachments
|
||||
*
|
||||
* @param string $mode can be: post|message|topic|attach|user
|
||||
* @param mixed $ids can be: post_ids, message_ids, topic_ids, attach_ids, user_ids
|
||||
* @param bool $resync set this to false if you are deleting posts or topics
|
||||
*
|
||||
* @return int|bool Number of deleted attachments or false if something
|
||||
* went wrong during attachment deletion
|
||||
*/
|
||||
public function delete($mode, $ids, $resync = true)
|
||||
{
|
||||
if (!$this->set_attachment_ids($ids))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->set_sql_constraints($mode);
|
||||
|
||||
$sql_id = $this->sql_id;
|
||||
|
||||
/**
|
||||
* Perform additional actions before collecting data for attachment(s) deletion
|
||||
*
|
||||
* @event core.delete_attachments_collect_data_before
|
||||
* @var string mode Variable containing attachments deletion mode, can be: post|message|topic|attach|user
|
||||
* @var mixed ids Array or comma separated list of ids corresponding to the mode
|
||||
* @var bool resync Flag indicating if posts/messages/topics should be synchronized
|
||||
* @var string sql_id The field name to collect/delete data for depending on the mode
|
||||
* @since 3.1.7-RC1
|
||||
*/
|
||||
$vars = array(
|
||||
'mode',
|
||||
'ids',
|
||||
'resync',
|
||||
'sql_id',
|
||||
);
|
||||
extract($this->dispatcher->trigger_event('core.delete_attachments_collect_data_before', compact($vars)));
|
||||
|
||||
$this->sql_id = $sql_id;
|
||||
unset($sql_id);
|
||||
|
||||
// Collect post and topic ids for later use if we need to touch remaining entries (if resync is enabled)
|
||||
$this->collect_attachment_info($resync);
|
||||
|
||||
// Delete attachments from database
|
||||
$this->delete_attachments_from_db($mode, $ids, $resync);
|
||||
|
||||
$sql_id = $this->sql_id;
|
||||
$post_ids = $this->post_ids;
|
||||
$topic_ids = $this->topic_ids;
|
||||
$message_ids = $this->message_ids;
|
||||
$physical = $this->physical;
|
||||
$num_deleted = $this->num_deleted;
|
||||
|
||||
/**
|
||||
* Perform additional actions after attachment(s) deletion from the database
|
||||
*
|
||||
* @event core.delete_attachments_from_database_after
|
||||
* @var string mode Variable containing attachments deletion mode, can be: post|message|topic|attach|user
|
||||
* @var mixed ids Array or comma separated list of ids corresponding to the mode
|
||||
* @var bool resync Flag indicating if posts/messages/topics should be synchronized
|
||||
* @var string sql_id The field name to collect/delete data for depending on the mode
|
||||
* @var array post_ids Array with post ids for deleted attachment(s)
|
||||
* @var array topic_ids Array with topic ids for deleted attachment(s)
|
||||
* @var array message_ids Array with private message ids for deleted attachment(s)
|
||||
* @var array physical Array with deleted attachment(s) physical file(s) data
|
||||
* @var int num_deleted The number of deleted attachment(s) from the database
|
||||
* @since 3.1.7-RC1
|
||||
*/
|
||||
$vars = array(
|
||||
'mode',
|
||||
'ids',
|
||||
'resync',
|
||||
'sql_id',
|
||||
'post_ids',
|
||||
'topic_ids',
|
||||
'message_ids',
|
||||
'physical',
|
||||
'num_deleted',
|
||||
);
|
||||
extract($this->dispatcher->trigger_event('core.delete_attachments_from_database_after', compact($vars)));
|
||||
|
||||
$this->sql_id = $sql_id;
|
||||
$this->post_ids = $post_ids;
|
||||
$this->topic_ids = $topic_ids;
|
||||
$this->message_ids = $message_ids;
|
||||
$this->physical = $physical;
|
||||
$this->num_deleted = $num_deleted;
|
||||
unset($sql_id, $post_ids, $topic_ids, $message_ids, $physical, $num_deleted);
|
||||
|
||||
if (!$this->num_deleted)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Delete attachments from filesystem
|
||||
$this->remove_from_filesystem($mode, $ids, $resync);
|
||||
|
||||
// If we do not resync, we do not need to adjust any message, post, topic or user entries
|
||||
if (!$resync)
|
||||
{
|
||||
return $this->num_deleted;
|
||||
}
|
||||
|
||||
// No more use for the original ids
|
||||
unset($ids);
|
||||
|
||||
// Update post indicators for posts now no longer having attachments
|
||||
$this->resync->resync('post', $this->post_ids);
|
||||
|
||||
// Update message table if messages are affected
|
||||
$this->resync->resync('message', $this->message_ids);
|
||||
|
||||
// Now update the topics. This is a bit trickier, because there could be posts still having attachments within the topic
|
||||
$this->resync->resync('topic', $this->topic_ids);
|
||||
|
||||
return $this->num_deleted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set attachment IDs
|
||||
*
|
||||
* @param mixed $ids ID or array of IDs
|
||||
*
|
||||
* @return bool True if attachment IDs were set, false if not
|
||||
*/
|
||||
protected function set_attachment_ids($ids)
|
||||
{
|
||||
// 0 is as bad as an empty array
|
||||
if (empty($ids))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_array($ids))
|
||||
{
|
||||
$ids = array_unique($ids);
|
||||
$this->ids = array_map('intval', $ids);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->ids = array((int) $ids);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set SQL constraints based on mode
|
||||
*
|
||||
* @param string $mode Delete mode; can be: post|message|topic|attach|user
|
||||
*/
|
||||
private function set_sql_constraints($mode)
|
||||
{
|
||||
switch ($mode)
|
||||
{
|
||||
case 'post':
|
||||
case 'message':
|
||||
$this->sql_id = 'post_msg_id';
|
||||
$this->sql_where = ' AND in_message = ' . ($mode == 'message' ? 1 : 0);
|
||||
break;
|
||||
|
||||
case 'topic':
|
||||
$this->sql_id = 'topic_id';
|
||||
break;
|
||||
|
||||
case 'user':
|
||||
$this->sql_id = 'poster_id';
|
||||
break;
|
||||
|
||||
case 'attach':
|
||||
default:
|
||||
$this->sql_id = 'attach_id';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect info about attachment IDs
|
||||
*
|
||||
* @param bool $resync Whether topics/posts should be resynced after delete
|
||||
*/
|
||||
protected function collect_attachment_info($resync)
|
||||
{
|
||||
// Collect post and topic ids for later use if we need to touch remaining entries (if resync is enabled)
|
||||
$sql = 'SELECT post_msg_id, topic_id, in_message, physical_filename, thumbnail, filesize, is_orphan
|
||||
FROM ' . ATTACHMENTS_TABLE . '
|
||||
WHERE ' . $this->db->sql_in_set($this->sql_id, $this->ids);
|
||||
|
||||
$sql .= $this->sql_where;
|
||||
|
||||
$result = $this->db->sql_query($sql);
|
||||
|
||||
while ($row = $this->db->sql_fetchrow($result))
|
||||
{
|
||||
// We only need to store post/message/topic ids if resync is enabled and the file is not orphaned
|
||||
if ($resync && !$row['is_orphan'])
|
||||
{
|
||||
if (!$row['in_message'])
|
||||
{
|
||||
$this->post_ids[] = $row['post_msg_id'];
|
||||
$this->topic_ids[] = $row['topic_id'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->message_ids[] = $row['post_msg_id'];
|
||||
}
|
||||
}
|
||||
|
||||
$this->physical[] = array('filename' => $row['physical_filename'], 'thumbnail' => $row['thumbnail'], 'filesize' => $row['filesize'], 'is_orphan' => $row['is_orphan']);
|
||||
}
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
// IDs should be unique
|
||||
$this->post_ids = array_unique($this->post_ids);
|
||||
$this->message_ids = array_unique($this->message_ids);
|
||||
$this->topic_ids = array_unique($this->topic_ids);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete attachments from database table
|
||||
*/
|
||||
protected function delete_attachments_from_db($mode, $ids, $resync)
|
||||
{
|
||||
$sql_id = $this->sql_id;
|
||||
$post_ids = $this->post_ids;
|
||||
$topic_ids = $this->topic_ids;
|
||||
$message_ids = $this->message_ids;
|
||||
$physical = $this->physical;
|
||||
|
||||
/**
|
||||
* Perform additional actions before attachment(s) deletion
|
||||
*
|
||||
* @event core.delete_attachments_before
|
||||
* @var string mode Variable containing attachments deletion mode, can be: post|message|topic|attach|user
|
||||
* @var mixed ids Array or comma separated list of ids corresponding to the mode
|
||||
* @var bool resync Flag indicating if posts/messages/topics should be synchronized
|
||||
* @var string sql_id The field name to collect/delete data for depending on the mode
|
||||
* @var array post_ids Array with post ids for deleted attachment(s)
|
||||
* @var array topic_ids Array with topic ids for deleted attachment(s)
|
||||
* @var array message_ids Array with private message ids for deleted attachment(s)
|
||||
* @var array physical Array with deleted attachment(s) physical file(s) data
|
||||
* @since 3.1.7-RC1
|
||||
*/
|
||||
$vars = array(
|
||||
'mode',
|
||||
'ids',
|
||||
'resync',
|
||||
'sql_id',
|
||||
'post_ids',
|
||||
'topic_ids',
|
||||
'message_ids',
|
||||
'physical',
|
||||
);
|
||||
extract($this->dispatcher->trigger_event('core.delete_attachments_before', compact($vars)));
|
||||
|
||||
$this->sql_id = $sql_id;
|
||||
$this->post_ids = $post_ids;
|
||||
$this->topic_ids = $topic_ids;
|
||||
$this->message_ids = $message_ids;
|
||||
$this->physical = $physical;
|
||||
unset($sql_id, $post_ids, $topic_ids, $message_ids, $physical);
|
||||
|
||||
// Delete attachments
|
||||
$sql = 'DELETE FROM ' . ATTACHMENTS_TABLE . '
|
||||
WHERE ' . $this->db->sql_in_set($this->sql_id, $this->ids);
|
||||
|
||||
$sql .= $this->sql_where;
|
||||
|
||||
$this->db->sql_query($sql);
|
||||
$this->num_deleted = $this->db->sql_affectedrows();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete attachments from filesystem
|
||||
*/
|
||||
protected function remove_from_filesystem($mode, $ids, $resync)
|
||||
{
|
||||
$space_removed = $files_removed = 0;
|
||||
|
||||
foreach ($this->physical as $file_ary)
|
||||
{
|
||||
if ($this->unlink_attachment($file_ary['filename'], 'file', true) && !$file_ary['is_orphan'])
|
||||
{
|
||||
// Only non-orphaned files count to the file size
|
||||
$space_removed += $file_ary['filesize'];
|
||||
$files_removed++;
|
||||
}
|
||||
|
||||
if ($file_ary['thumbnail'])
|
||||
{
|
||||
$this->unlink_attachment($file_ary['filename'], 'thumbnail', true);
|
||||
}
|
||||
}
|
||||
|
||||
$sql_id = $this->sql_id;
|
||||
$post_ids = $this->post_ids;
|
||||
$topic_ids = $this->topic_ids;
|
||||
$message_ids = $this->message_ids;
|
||||
$physical = $this->physical;
|
||||
$num_deleted = $this->num_deleted;
|
||||
|
||||
/**
|
||||
* Perform additional actions after attachment(s) deletion from the filesystem
|
||||
*
|
||||
* @event core.delete_attachments_from_filesystem_after
|
||||
* @var string mode Variable containing attachments deletion mode, can be: post|message|topic|attach|user
|
||||
* @var mixed ids Array or comma separated list of ids corresponding to the mode
|
||||
* @var bool resync Flag indicating if posts/messages/topics should be synchronized
|
||||
* @var string sql_id The field name to collect/delete data for depending on the mode
|
||||
* @var array post_ids Array with post ids for deleted attachment(s)
|
||||
* @var array topic_ids Array with topic ids for deleted attachment(s)
|
||||
* @var array message_ids Array with private message ids for deleted attachment(s)
|
||||
* @var array physical Array with deleted attachment(s) physical file(s) data
|
||||
* @var int num_deleted The number of deleted attachment(s) from the database
|
||||
* @var int space_removed The size of deleted files(s) from the filesystem
|
||||
* @var int files_removed The number of deleted file(s) from the filesystem
|
||||
* @since 3.1.7-RC1
|
||||
*/
|
||||
$vars = array(
|
||||
'mode',
|
||||
'ids',
|
||||
'resync',
|
||||
'sql_id',
|
||||
'post_ids',
|
||||
'topic_ids',
|
||||
'message_ids',
|
||||
'physical',
|
||||
'num_deleted',
|
||||
'space_removed',
|
||||
'files_removed',
|
||||
);
|
||||
extract($this->dispatcher->trigger_event('core.delete_attachments_from_filesystem_after', compact($vars)));
|
||||
|
||||
$this->sql_id = $sql_id;
|
||||
$this->post_ids = $post_ids;
|
||||
$this->topic_ids = $topic_ids;
|
||||
$this->message_ids = $message_ids;
|
||||
$this->physical = $physical;
|
||||
$this->num_deleted = $num_deleted;
|
||||
unset($sql_id, $post_ids, $topic_ids, $message_ids, $physical, $num_deleted);
|
||||
|
||||
if ($space_removed || $files_removed)
|
||||
{
|
||||
$this->config->increment('upload_dir_size', $space_removed * (-1), false);
|
||||
$this->config->increment('num_files', $files_removed * (-1), false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete attachment from filesystem
|
||||
*
|
||||
* @param string $filename Filename of attachment
|
||||
* @param string $mode Delete mode
|
||||
* @param bool $entry_removed Whether entry was removed. Defaults to false
|
||||
* @return bool True if file was removed, false if not
|
||||
*/
|
||||
public function unlink_attachment($filename, $mode = 'file', $entry_removed = false)
|
||||
{
|
||||
// Because of copying topics or modifications a physical filename could be assigned more than once. If so, do not remove the file itself.
|
||||
$sql = 'SELECT COUNT(attach_id) AS num_entries
|
||||
FROM ' . ATTACHMENTS_TABLE . "
|
||||
WHERE physical_filename = '" . $this->db->sql_escape(utf8_basename($filename)) . "'";
|
||||
$result = $this->db->sql_query($sql);
|
||||
$num_entries = (int) $this->db->sql_fetchfield('num_entries');
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
// Do not remove file if at least one additional entry with the same name exist.
|
||||
if (($entry_removed && $num_entries > 0) || (!$entry_removed && $num_entries > 1))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$filename = ($mode == 'thumbnail') ? 'thumb_' . utf8_basename($filename) : utf8_basename($filename);
|
||||
$filepath = $this->phpbb_root_path . $this->config['upload_path'] . '/' . $filename;
|
||||
|
||||
try
|
||||
{
|
||||
if ($this->filesystem->exists($filepath))
|
||||
{
|
||||
$this->filesystem->remove($this->phpbb_root_path . $this->config['upload_path'] . '/' . $filename);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (\phpbb\filesystem\exception\filesystem_exception $exception)
|
||||
{
|
||||
// Fail is covered by return statement below
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
99
phpbb/attachment/manager.php
Normal file
99
phpbb/attachment/manager.php
Normal file
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\attachment;
|
||||
|
||||
/**
|
||||
* Attachment manager
|
||||
*/
|
||||
class manager
|
||||
{
|
||||
/** @var delete Attachment delete class */
|
||||
protected $delete;
|
||||
|
||||
/** @var resync Attachment resync class */
|
||||
protected $resync;
|
||||
|
||||
/** @var upload Attachment upload class */
|
||||
protected $upload;
|
||||
|
||||
/**
|
||||
* Constructor for attachment manager
|
||||
*
|
||||
* @param delete $delete Attachment delete class
|
||||
* @param resync $resync Attachment resync class
|
||||
* @param upload $upload Attachment upload class
|
||||
*/
|
||||
public function __construct(delete $delete, resync $resync, upload $upload)
|
||||
{
|
||||
$this->delete = $delete;
|
||||
$this->resync = $resync;
|
||||
$this->upload = $upload;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper method for deleting attachments
|
||||
*
|
||||
* @param string $mode can be: post|message|topic|attach|user
|
||||
* @param mixed $ids can be: post_ids, message_ids, topic_ids, attach_ids, user_ids
|
||||
* @param bool $resync set this to false if you are deleting posts or topics
|
||||
*
|
||||
* @return int|bool Number of deleted attachments or false if something
|
||||
* went wrong during attachment deletion
|
||||
*/
|
||||
public function delete($mode, $ids, $resync = true)
|
||||
{
|
||||
return $this->delete->delete($mode, $ids, $resync);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper method for deleting attachments from filesystem
|
||||
*
|
||||
* @param string $filename Filename of attachment
|
||||
* @param string $mode Delete mode
|
||||
* @param bool $entry_removed Whether entry was removed. Defaults to false
|
||||
* @return bool True if file was removed, false if not
|
||||
*/
|
||||
public function unlink($filename, $mode = 'file', $entry_removed = false)
|
||||
{
|
||||
return $this->delete->unlink_attachment($filename, $mode, $entry_removed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper method for resyncing specified type
|
||||
*
|
||||
* @param string $type Type of resync
|
||||
* @param array $ids IDs to resync
|
||||
*/
|
||||
public function resync($type, $ids)
|
||||
{
|
||||
$this->resync->resync($type, $ids);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper method for uploading attachment
|
||||
*
|
||||
* @param string $form_name The form name of the file upload input
|
||||
* @param int $forum_id The id of the forum
|
||||
* @param bool $local Whether the file is local or not
|
||||
* @param string $local_storage The path to the local file
|
||||
* @param bool $is_message Whether it is a PM or not
|
||||
* @param array $local_filedata An file data object created for the local file
|
||||
*
|
||||
* @return array File data array
|
||||
*/
|
||||
public function upload($form_name, $forum_id, $local = false, $local_storage = '', $is_message = false, $local_filedata = [])
|
||||
{
|
||||
return $this->upload->upload($form_name, $forum_id, $local, $local_storage, $is_message, $local_filedata);
|
||||
}
|
||||
}
|
||||
124
phpbb/attachment/resync.php
Normal file
124
phpbb/attachment/resync.php
Normal file
@@ -0,0 +1,124 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\attachment;
|
||||
|
||||
use \phpbb\db\driver\driver_interface;
|
||||
|
||||
/**
|
||||
* Attachment resync class
|
||||
*/
|
||||
class resync
|
||||
{
|
||||
/** @var driver_interface */
|
||||
protected $db;
|
||||
|
||||
/** @var string Attachment table SQL ID */
|
||||
private $attach_sql_id;
|
||||
|
||||
/** @var string Resync table SQL ID */
|
||||
private $resync_sql_id;
|
||||
|
||||
/** @var string Resync SQL table */
|
||||
private $resync_table;
|
||||
|
||||
/** @var string SQL where statement */
|
||||
private $sql_where;
|
||||
|
||||
/**
|
||||
* Constructor for attachment resync class
|
||||
*
|
||||
* @param driver_interface $db Database driver
|
||||
*/
|
||||
public function __construct(driver_interface $db)
|
||||
{
|
||||
$this->db = $db;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set type constraints for attachment resync
|
||||
*
|
||||
* @param string $type Type of resync; can be: message|post|topic
|
||||
*/
|
||||
protected function set_type_constraints($type)
|
||||
{
|
||||
switch ($type)
|
||||
{
|
||||
case 'message':
|
||||
$this->attach_sql_id = 'post_msg_id';
|
||||
$this->sql_where = ' AND in_message = 1
|
||||
AND is_orphan = 0';
|
||||
$this->resync_table = PRIVMSGS_TABLE;
|
||||
$this->resync_sql_id = 'msg_id';
|
||||
break;
|
||||
|
||||
case 'post':
|
||||
$this->attach_sql_id = 'post_msg_id';
|
||||
$this->sql_where = ' AND in_message = 0
|
||||
AND is_orphan = 0';
|
||||
$this->resync_table = POSTS_TABLE;
|
||||
$this->resync_sql_id = 'post_id';
|
||||
break;
|
||||
|
||||
case 'topic':
|
||||
$this->attach_sql_id = 'topic_id';
|
||||
$this->sql_where = ' AND is_orphan = 0';
|
||||
$this->resync_table = TOPICS_TABLE;
|
||||
$this->resync_sql_id = 'topic_id';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resync specified type
|
||||
*
|
||||
* @param string $type Type of resync
|
||||
* @param array $ids IDs to resync
|
||||
*/
|
||||
public function resync($type, $ids)
|
||||
{
|
||||
if (empty($type) || !is_array($ids) || !count($ids) || !in_array($type, array('post', 'topic', 'message')))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$this->set_type_constraints($type);
|
||||
|
||||
// Just check which elements are still having an assigned attachment
|
||||
// not orphaned by querying the attachments table
|
||||
$sql = 'SELECT ' . $this->attach_sql_id . '
|
||||
FROM ' . ATTACHMENTS_TABLE . '
|
||||
WHERE ' . $this->db->sql_in_set($this->attach_sql_id, $ids)
|
||||
. $this->sql_where;
|
||||
$result = $this->db->sql_query($sql);
|
||||
|
||||
$remaining_ids = array();
|
||||
while ($row = $this->db->sql_fetchrow($result))
|
||||
{
|
||||
$remaining_ids[] = $row[$this->attach_sql_id];
|
||||
}
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
// Now only unset those ids remaining
|
||||
$ids = array_diff($ids, $remaining_ids);
|
||||
|
||||
if (count($ids))
|
||||
{
|
||||
$sql = 'UPDATE ' . $this->resync_table . '
|
||||
SET ' . $type . '_attachment = 0
|
||||
WHERE ' . $this->db->sql_in_set($this->resync_sql_id, $ids);
|
||||
$this->db->sql_query($sql);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
334
phpbb/attachment/upload.php
Normal file
334
phpbb/attachment/upload.php
Normal file
@@ -0,0 +1,334 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\attachment;
|
||||
|
||||
use phpbb\auth\auth;
|
||||
use \phpbb\cache\service;
|
||||
use \phpbb\config\config;
|
||||
use \phpbb\event\dispatcher;
|
||||
use \phpbb\language\language;
|
||||
use \phpbb\mimetype\guesser;
|
||||
use \phpbb\plupload\plupload;
|
||||
use \phpbb\user;
|
||||
|
||||
/**
|
||||
* Attachment upload class
|
||||
*/
|
||||
class upload
|
||||
{
|
||||
/** @var auth */
|
||||
protected $auth;
|
||||
|
||||
/** @var service */
|
||||
protected $cache;
|
||||
|
||||
/** @var config */
|
||||
protected $config;
|
||||
|
||||
/** @var \phpbb\files\upload Upload class */
|
||||
protected $files_upload;
|
||||
|
||||
/** @var language */
|
||||
protected $language;
|
||||
|
||||
/** @var guesser Mimetype guesser */
|
||||
protected $mimetype_guesser;
|
||||
|
||||
/** @var dispatcher */
|
||||
protected $phpbb_dispatcher;
|
||||
|
||||
/** @var plupload Plupload */
|
||||
protected $plupload;
|
||||
|
||||
/** @var user */
|
||||
protected $user;
|
||||
|
||||
/** @var \phpbb\files\filespec Current filespec instance */
|
||||
private $file;
|
||||
|
||||
/** @var array File data */
|
||||
private $file_data = array(
|
||||
'error' => array()
|
||||
);
|
||||
|
||||
/** @var array Extensions array */
|
||||
private $extensions;
|
||||
|
||||
/**
|
||||
* Constructor for attachments upload class
|
||||
*
|
||||
* @param auth $auth
|
||||
* @param service $cache
|
||||
* @param config $config
|
||||
* @param \phpbb\files\upload $files_upload
|
||||
* @param language $language
|
||||
* @param guesser $mimetype_guesser
|
||||
* @param dispatcher $phpbb_dispatcher
|
||||
* @param plupload $plupload
|
||||
* @param user $user
|
||||
* @param $phpbb_root_path
|
||||
*/
|
||||
public function __construct(auth $auth, service $cache, config $config, \phpbb\files\upload $files_upload, language $language, guesser $mimetype_guesser, dispatcher $phpbb_dispatcher, plupload $plupload, user $user, $phpbb_root_path)
|
||||
{
|
||||
$this->auth = $auth;
|
||||
$this->cache = $cache;
|
||||
$this->config = $config;
|
||||
$this->files_upload = $files_upload;
|
||||
$this->language = $language;
|
||||
$this->mimetype_guesser = $mimetype_guesser;
|
||||
$this->phpbb_dispatcher = $phpbb_dispatcher;
|
||||
$this->plupload = $plupload;
|
||||
$this->user = $user;
|
||||
$this->phpbb_root_path = $phpbb_root_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload Attachment - filedata is generated here
|
||||
* Uses upload class
|
||||
*
|
||||
* @param string $form_name The form name of the file upload input
|
||||
* @param int $forum_id The id of the forum
|
||||
* @param bool $local Whether the file is local or not
|
||||
* @param string $local_storage The path to the local file
|
||||
* @param bool $is_message Whether it is a PM or not
|
||||
* @param array $local_filedata An file data object created for the local file
|
||||
*
|
||||
* @return array File data array
|
||||
*/
|
||||
public function upload($form_name, $forum_id, $local = false, $local_storage = '', $is_message = false, $local_filedata = array())
|
||||
{
|
||||
$this->init_files_upload($forum_id, $is_message);
|
||||
|
||||
$this->file_data['post_attach'] = $local || $this->files_upload->is_valid($form_name);
|
||||
|
||||
if (!$this->file_data['post_attach'])
|
||||
{
|
||||
$this->file_data['error'][] = $this->language->lang('NO_UPLOAD_FORM_FOUND');
|
||||
return $this->file_data;
|
||||
}
|
||||
|
||||
$this->file = ($local) ? $this->files_upload->handle_upload('files.types.local', $local_storage, $local_filedata) : $this->files_upload->handle_upload('files.types.form', $form_name);
|
||||
|
||||
if ($this->file->init_error())
|
||||
{
|
||||
$this->file_data['post_attach'] = false;
|
||||
return $this->file_data;
|
||||
}
|
||||
|
||||
// Whether the uploaded file is in the image category
|
||||
$is_image = (isset($this->extensions[$this->file->get('extension')]['display_cat'])) ? $this->extensions[$this->file->get('extension')]['display_cat'] == ATTACHMENT_CATEGORY_IMAGE : false;
|
||||
|
||||
if (!$this->auth->acl_get('a_') && !$this->auth->acl_get('m_', $forum_id))
|
||||
{
|
||||
// Check Image Size, if it is an image
|
||||
if ($is_image)
|
||||
{
|
||||
$this->file->upload->set_allowed_dimensions(0, 0, $this->config['img_max_width'], $this->config['img_max_height']);
|
||||
}
|
||||
|
||||
// Admins and mods are allowed to exceed the allowed filesize
|
||||
if (!empty($this->extensions[$this->file->get('extension')]['max_filesize']))
|
||||
{
|
||||
$allowed_filesize = $this->extensions[$this->file->get('extension')]['max_filesize'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$allowed_filesize = ($is_message) ? $this->config['max_filesize_pm'] : $this->config['max_filesize'];
|
||||
}
|
||||
|
||||
$this->file->upload->set_max_filesize($allowed_filesize);
|
||||
}
|
||||
|
||||
$this->file->clean_filename('unique', $this->user->data['user_id'] . '_');
|
||||
|
||||
// Are we uploading an image *and* this image being within the image category?
|
||||
// Only then perform additional image checks.
|
||||
$this->file->move_file($this->config['upload_path'], false, !$is_image);
|
||||
|
||||
// Do we have to create a thumbnail?
|
||||
$this->file_data['thumbnail'] = ($is_image && $this->config['img_create_thumbnail']) ? 1 : 0;
|
||||
|
||||
// Make sure the image category only holds valid images...
|
||||
$this->check_image($is_image);
|
||||
|
||||
if (count($this->file->error))
|
||||
{
|
||||
$this->file->remove();
|
||||
$this->file_data['error'] = array_merge($this->file_data['error'], $this->file->error);
|
||||
$this->file_data['post_attach'] = false;
|
||||
|
||||
return $this->file_data;
|
||||
}
|
||||
|
||||
$this->fill_file_data();
|
||||
|
||||
$filedata = $this->file_data;
|
||||
|
||||
/**
|
||||
* Event to modify uploaded file before submit to the post
|
||||
*
|
||||
* @event core.modify_uploaded_file
|
||||
* @var array filedata Array containing uploaded file data
|
||||
* @var bool is_image Flag indicating if the file is an image
|
||||
* @since 3.1.0-RC3
|
||||
*/
|
||||
$vars = array(
|
||||
'filedata',
|
||||
'is_image',
|
||||
);
|
||||
extract($this->phpbb_dispatcher->trigger_event('core.modify_uploaded_file', compact($vars)));
|
||||
$this->file_data = $filedata;
|
||||
unset($filedata);
|
||||
|
||||
// Check for attachment quota and free space
|
||||
if (!$this->check_attach_quota() || !$this->check_disk_space())
|
||||
{
|
||||
return $this->file_data;
|
||||
}
|
||||
|
||||
// Create Thumbnail
|
||||
$this->create_thumbnail();
|
||||
|
||||
return $this->file_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create thumbnail for file if necessary
|
||||
*
|
||||
* @return array Updated $filedata
|
||||
*/
|
||||
protected function create_thumbnail()
|
||||
{
|
||||
if ($this->file_data['thumbnail'])
|
||||
{
|
||||
$source = $this->file->get('destination_file');
|
||||
$destination = $this->file->get('destination_path') . '/thumb_' . $this->file->get('realname');
|
||||
|
||||
if (!create_thumbnail($source, $destination, $this->file->get('mimetype')))
|
||||
{
|
||||
$this->file_data['thumbnail'] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Init files upload class
|
||||
*
|
||||
* @param int $forum_id Forum ID
|
||||
* @param bool $is_message Whether attachment is inside PM or not
|
||||
*/
|
||||
protected function init_files_upload($forum_id, $is_message)
|
||||
{
|
||||
if ($this->config['check_attachment_content'] && isset($this->config['mime_triggers']))
|
||||
{
|
||||
$this->files_upload->set_disallowed_content(explode('|', $this->config['mime_triggers']));
|
||||
}
|
||||
else if (!$this->config['check_attachment_content'])
|
||||
{
|
||||
$this->files_upload->set_disallowed_content(array());
|
||||
}
|
||||
|
||||
$this->extensions = $this->cache->obtain_attach_extensions((($is_message) ? false : (int) $forum_id));
|
||||
$this->files_upload->set_allowed_extensions(array_keys($this->extensions['_allowed_']));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if uploaded file is really an image
|
||||
*
|
||||
* @param bool $is_image Whether file is image
|
||||
*/
|
||||
protected function check_image($is_image)
|
||||
{
|
||||
// Make sure the image category only holds valid images...
|
||||
if ($is_image && !$this->file->is_image())
|
||||
{
|
||||
$this->file->remove();
|
||||
|
||||
if ($this->plupload && $this->plupload->is_active())
|
||||
{
|
||||
$this->plupload->emit_error(104, 'ATTACHED_IMAGE_NOT_IMAGE');
|
||||
}
|
||||
|
||||
// If this error occurs a user tried to exploit an IE Bug by renaming extensions
|
||||
// Since the image category is displaying content inline we need to catch this.
|
||||
$this->file->set_error($this->language->lang('ATTACHED_IMAGE_NOT_IMAGE'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if attachment quota was reached
|
||||
*
|
||||
* @return bool False if attachment quota was reached, true if not
|
||||
*/
|
||||
protected function check_attach_quota()
|
||||
{
|
||||
if ($this->config['attachment_quota'])
|
||||
{
|
||||
if (intval($this->config['upload_dir_size']) + $this->file->get('filesize') > $this->config['attachment_quota'])
|
||||
{
|
||||
$this->file_data['error'][] = $this->language->lang('ATTACH_QUOTA_REACHED');
|
||||
$this->file_data['post_attach'] = false;
|
||||
|
||||
$this->file->remove();
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if there is enough free space available on disk
|
||||
*
|
||||
* @return bool True if disk space is available, false if not
|
||||
*/
|
||||
protected function check_disk_space()
|
||||
{
|
||||
if ($free_space = @disk_free_space($this->phpbb_root_path . $this->config['upload_path']))
|
||||
{
|
||||
if ($free_space <= $this->file->get('filesize'))
|
||||
{
|
||||
if ($this->auth->acl_get('a_'))
|
||||
{
|
||||
$this->file_data['error'][] = $this->language->lang('ATTACH_DISK_FULL');
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->file_data['error'][] = $this->language->lang('ATTACH_QUOTA_REACHED');
|
||||
}
|
||||
$this->file_data['post_attach'] = false;
|
||||
|
||||
$this->file->remove();
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills file data with file information and current time as filetime
|
||||
*/
|
||||
protected function fill_file_data()
|
||||
{
|
||||
$this->file_data['filesize'] = $this->file->get('filesize');
|
||||
$this->file_data['mimetype'] = $this->file->get('mimetype');
|
||||
$this->file_data['extension'] = $this->file->get('extension');
|
||||
$this->file_data['physical_filename'] = $this->file->get('realname');
|
||||
$this->file_data['real_filename'] = $this->file->get('uploadname');
|
||||
$this->file_data['filetime'] = time();
|
||||
}
|
||||
}
|
||||
1122
phpbb/auth/auth.php
Normal file
1122
phpbb/auth/auth.php
Normal file
File diff suppressed because it is too large
Load Diff
10
phpbb/auth/index.htm
Normal file
10
phpbb/auth/index.htm
Normal file
@@ -0,0 +1,10 @@
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
</head>
|
||||
|
||||
<body bgcolor="#FFFFFF" text="#000000">
|
||||
|
||||
</body>
|
||||
</html>
|
||||
264
phpbb/auth/provider/apache.php
Normal file
264
phpbb/auth/provider/apache.php
Normal file
@@ -0,0 +1,264 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\auth\provider;
|
||||
|
||||
/**
|
||||
* Apache authentication provider for phpBB3
|
||||
*/
|
||||
class apache extends \phpbb\auth\provider\base
|
||||
{
|
||||
/**
|
||||
* phpBB passwords manager
|
||||
*
|
||||
* @var \phpbb\passwords\manager
|
||||
*/
|
||||
protected $passwords_manager;
|
||||
|
||||
/**
|
||||
* Apache Authentication Constructor
|
||||
*
|
||||
* @param \phpbb\db\driver\driver_interface $db Database object
|
||||
* @param \phpbb\config\config $config Config object
|
||||
* @param \phpbb\passwords\manager $passwords_manager Passwords Manager object
|
||||
* @param \phpbb\request\request $request Request object
|
||||
* @param \phpbb\user $user User object
|
||||
* @param string $phpbb_root_path Relative path to phpBB root
|
||||
* @param string $php_ext PHP file extension
|
||||
*/
|
||||
public function __construct(\phpbb\db\driver\driver_interface $db, \phpbb\config\config $config, \phpbb\passwords\manager $passwords_manager, \phpbb\request\request $request, \phpbb\user $user, $phpbb_root_path, $php_ext)
|
||||
{
|
||||
$this->db = $db;
|
||||
$this->config = $config;
|
||||
$this->passwords_manager = $passwords_manager;
|
||||
$this->request = $request;
|
||||
$this->user = $user;
|
||||
$this->phpbb_root_path = $phpbb_root_path;
|
||||
$this->php_ext = $php_ext;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
if (!$this->request->is_set('PHP_AUTH_USER', \phpbb\request\request_interface::SERVER) || $this->user->data['username'] !== htmlspecialchars_decode($this->request->server('PHP_AUTH_USER')))
|
||||
{
|
||||
return $this->user->lang['APACHE_SETUP_BEFORE_USE'];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function login($username, $password)
|
||||
{
|
||||
// do not allow empty password
|
||||
if (!$password)
|
||||
{
|
||||
return array(
|
||||
'status' => LOGIN_ERROR_PASSWORD,
|
||||
'error_msg' => 'NO_PASSWORD_SUPPLIED',
|
||||
'user_row' => array('user_id' => ANONYMOUS),
|
||||
);
|
||||
}
|
||||
|
||||
if (!$username)
|
||||
{
|
||||
return array(
|
||||
'status' => LOGIN_ERROR_USERNAME,
|
||||
'error_msg' => 'LOGIN_ERROR_USERNAME',
|
||||
'user_row' => array('user_id' => ANONYMOUS),
|
||||
);
|
||||
}
|
||||
|
||||
if (!$this->request->is_set('PHP_AUTH_USER', \phpbb\request\request_interface::SERVER))
|
||||
{
|
||||
return array(
|
||||
'status' => LOGIN_ERROR_EXTERNAL_AUTH,
|
||||
'error_msg' => 'LOGIN_ERROR_EXTERNAL_AUTH_APACHE',
|
||||
'user_row' => array('user_id' => ANONYMOUS),
|
||||
);
|
||||
}
|
||||
|
||||
$php_auth_user = htmlspecialchars_decode($this->request->server('PHP_AUTH_USER'));
|
||||
$php_auth_pw = htmlspecialchars_decode($this->request->server('PHP_AUTH_PW'));
|
||||
|
||||
if (!empty($php_auth_user) && !empty($php_auth_pw))
|
||||
{
|
||||
if ($php_auth_user !== $username)
|
||||
{
|
||||
return array(
|
||||
'status' => LOGIN_ERROR_USERNAME,
|
||||
'error_msg' => 'LOGIN_ERROR_USERNAME',
|
||||
'user_row' => array('user_id' => ANONYMOUS),
|
||||
);
|
||||
}
|
||||
|
||||
$sql = 'SELECT user_id, username, user_password, user_passchg, user_email, user_type
|
||||
FROM ' . USERS_TABLE . "
|
||||
WHERE username = '" . $this->db->sql_escape($php_auth_user) . "'";
|
||||
$result = $this->db->sql_query($sql);
|
||||
$row = $this->db->sql_fetchrow($result);
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
if ($row)
|
||||
{
|
||||
// User inactive...
|
||||
if ($row['user_type'] == USER_INACTIVE || $row['user_type'] == USER_IGNORE)
|
||||
{
|
||||
return array(
|
||||
'status' => LOGIN_ERROR_ACTIVE,
|
||||
'error_msg' => 'ACTIVE_ERROR',
|
||||
'user_row' => $row,
|
||||
);
|
||||
}
|
||||
|
||||
// Successful login...
|
||||
return array(
|
||||
'status' => LOGIN_SUCCESS,
|
||||
'error_msg' => false,
|
||||
'user_row' => $row,
|
||||
);
|
||||
}
|
||||
|
||||
// this is the user's first login so create an empty profile
|
||||
return array(
|
||||
'status' => LOGIN_SUCCESS_CREATE_PROFILE,
|
||||
'error_msg' => false,
|
||||
'user_row' => $this->user_row($php_auth_user, $php_auth_pw),
|
||||
);
|
||||
}
|
||||
|
||||
// Not logged into apache
|
||||
return array(
|
||||
'status' => LOGIN_ERROR_EXTERNAL_AUTH,
|
||||
'error_msg' => 'LOGIN_ERROR_EXTERNAL_AUTH_APACHE',
|
||||
'user_row' => array('user_id' => ANONYMOUS),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function autologin()
|
||||
{
|
||||
if (!$this->request->is_set('PHP_AUTH_USER', \phpbb\request\request_interface::SERVER))
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
$php_auth_user = htmlspecialchars_decode($this->request->server('PHP_AUTH_USER'));
|
||||
$php_auth_pw = htmlspecialchars_decode($this->request->server('PHP_AUTH_PW'));
|
||||
|
||||
if (!empty($php_auth_user) && !empty($php_auth_pw))
|
||||
{
|
||||
set_var($php_auth_user, $php_auth_user, 'string', true);
|
||||
set_var($php_auth_pw, $php_auth_pw, 'string', true);
|
||||
|
||||
$sql = 'SELECT *
|
||||
FROM ' . USERS_TABLE . "
|
||||
WHERE username = '" . $this->db->sql_escape($php_auth_user) . "'";
|
||||
$result = $this->db->sql_query($sql);
|
||||
$row = $this->db->sql_fetchrow($result);
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
if ($row)
|
||||
{
|
||||
return ($row['user_type'] == USER_INACTIVE || $row['user_type'] == USER_IGNORE) ? array() : $row;
|
||||
}
|
||||
|
||||
if (!function_exists('user_add'))
|
||||
{
|
||||
include($this->phpbb_root_path . 'includes/functions_user.' . $this->php_ext);
|
||||
}
|
||||
|
||||
// create the user if he does not exist yet
|
||||
user_add($this->user_row($php_auth_user, $php_auth_pw));
|
||||
|
||||
$sql = 'SELECT *
|
||||
FROM ' . USERS_TABLE . "
|
||||
WHERE username_clean = '" . $this->db->sql_escape(utf8_clean_string($php_auth_user)) . "'";
|
||||
$result = $this->db->sql_query($sql);
|
||||
$row = $this->db->sql_fetchrow($result);
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
if ($row)
|
||||
{
|
||||
return $row;
|
||||
}
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* This function generates an array which can be passed to the user_add
|
||||
* function in order to create a user
|
||||
*
|
||||
* @param string $username The username of the new user.
|
||||
* @param string $password The password of the new user.
|
||||
* @return array Contains data that can be passed directly to
|
||||
* the user_add function.
|
||||
*/
|
||||
private function user_row($username, $password)
|
||||
{
|
||||
// first retrieve default group id
|
||||
$sql = 'SELECT group_id
|
||||
FROM ' . GROUPS_TABLE . "
|
||||
WHERE group_name = '" . $this->db->sql_escape('REGISTERED') . "'
|
||||
AND group_type = " . GROUP_SPECIAL;
|
||||
$result = $this->db->sql_query($sql);
|
||||
$row = $this->db->sql_fetchrow($result);
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
if (!$row)
|
||||
{
|
||||
trigger_error('NO_GROUP');
|
||||
}
|
||||
|
||||
// generate user account data
|
||||
return array(
|
||||
'username' => $username,
|
||||
'user_password' => $this->passwords_manager->hash($password),
|
||||
'user_email' => '',
|
||||
'group_id' => (int) $row['group_id'],
|
||||
'user_type' => USER_NORMAL,
|
||||
'user_ip' => $this->user->ip,
|
||||
'user_new' => ($this->config['new_member_post_limit']) ? 1 : 0,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validate_session($user)
|
||||
{
|
||||
// Check if PHP_AUTH_USER is set and handle this case
|
||||
if ($this->request->is_set('PHP_AUTH_USER', \phpbb\request\request_interface::SERVER))
|
||||
{
|
||||
$php_auth_user = $this->request->server('PHP_AUTH_USER');
|
||||
|
||||
return ($php_auth_user === $user['username']) ? true : false;
|
||||
}
|
||||
|
||||
// PHP_AUTH_USER is not set. A valid session is now determined by the user type (anonymous/bot or not)
|
||||
if ($user['user_type'] == USER_IGNORE)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
108
phpbb/auth/provider/base.php
Normal file
108
phpbb/auth/provider/base.php
Normal file
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\auth\provider;
|
||||
|
||||
/**
|
||||
* Base authentication provider class that all other providers should implement
|
||||
*/
|
||||
abstract class base implements \phpbb\auth\provider\provider_interface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function autologin()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function acp()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get_acp_template($new_config)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get_login_data()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get_auth_link_data($user_id = 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function logout($data, $new_session)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validate_session($user)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function login_link_has_necessary_data($login_link_data)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function link_account(array $link_data)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function unlink_account(array $link_data)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
240
phpbb/auth/provider/db.php
Normal file
240
phpbb/auth/provider/db.php
Normal file
@@ -0,0 +1,240 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\auth\provider;
|
||||
|
||||
/**
|
||||
* Database authentication provider for phpBB3
|
||||
* This is for authentication via the integrated user table
|
||||
*/
|
||||
class db extends \phpbb\auth\provider\base
|
||||
{
|
||||
/**
|
||||
* phpBB passwords manager
|
||||
*
|
||||
* @var \phpbb\passwords\manager
|
||||
*/
|
||||
protected $passwords_manager;
|
||||
|
||||
/**
|
||||
* DI container
|
||||
*
|
||||
* @var \Symfony\Component\DependencyInjection\ContainerInterface
|
||||
*/
|
||||
protected $phpbb_container;
|
||||
|
||||
/**
|
||||
* Database Authentication Constructor
|
||||
*
|
||||
* @param \phpbb\db\driver\driver_interface $db
|
||||
* @param \phpbb\config\config $config
|
||||
* @param \phpbb\passwords\manager $passwords_manager
|
||||
* @param \phpbb\request\request $request
|
||||
* @param \phpbb\user $user
|
||||
* @param \Symfony\Component\DependencyInjection\ContainerInterface $phpbb_container DI container
|
||||
* @param string $phpbb_root_path
|
||||
* @param string $php_ext
|
||||
*/
|
||||
public function __construct(\phpbb\db\driver\driver_interface $db, \phpbb\config\config $config, \phpbb\passwords\manager $passwords_manager, \phpbb\request\request $request, \phpbb\user $user, \Symfony\Component\DependencyInjection\ContainerInterface $phpbb_container, $phpbb_root_path, $php_ext)
|
||||
{
|
||||
$this->db = $db;
|
||||
$this->config = $config;
|
||||
$this->passwords_manager = $passwords_manager;
|
||||
$this->request = $request;
|
||||
$this->user = $user;
|
||||
$this->phpbb_root_path = $phpbb_root_path;
|
||||
$this->php_ext = $php_ext;
|
||||
$this->phpbb_container = $phpbb_container;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function login($username, $password)
|
||||
{
|
||||
// Auth plugins get the password untrimmed.
|
||||
// For compatibility we trim() here.
|
||||
$password = trim($password);
|
||||
|
||||
// do not allow empty password
|
||||
if (!$password)
|
||||
{
|
||||
return array(
|
||||
'status' => LOGIN_ERROR_PASSWORD,
|
||||
'error_msg' => 'NO_PASSWORD_SUPPLIED',
|
||||
'user_row' => array('user_id' => ANONYMOUS),
|
||||
);
|
||||
}
|
||||
|
||||
if (!$username)
|
||||
{
|
||||
return array(
|
||||
'status' => LOGIN_ERROR_USERNAME,
|
||||
'error_msg' => 'LOGIN_ERROR_USERNAME',
|
||||
'user_row' => array('user_id' => ANONYMOUS),
|
||||
);
|
||||
}
|
||||
|
||||
$username_clean = utf8_clean_string($username);
|
||||
|
||||
$sql = 'SELECT *
|
||||
FROM ' . USERS_TABLE . "
|
||||
WHERE username_clean = '" . $this->db->sql_escape($username_clean) . "'";
|
||||
$result = $this->db->sql_query($sql);
|
||||
$row = $this->db->sql_fetchrow($result);
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
if (($this->user->ip && !$this->config['ip_login_limit_use_forwarded']) ||
|
||||
($this->user->forwarded_for && $this->config['ip_login_limit_use_forwarded']))
|
||||
{
|
||||
$sql = 'SELECT COUNT(*) AS attempts
|
||||
FROM ' . LOGIN_ATTEMPT_TABLE . '
|
||||
WHERE attempt_time > ' . (time() - (int) $this->config['ip_login_limit_time']);
|
||||
if ($this->config['ip_login_limit_use_forwarded'])
|
||||
{
|
||||
$sql .= " AND attempt_forwarded_for = '" . $this->db->sql_escape($this->user->forwarded_for) . "'";
|
||||
}
|
||||
else
|
||||
{
|
||||
$sql .= " AND attempt_ip = '" . $this->db->sql_escape($this->user->ip) . "' ";
|
||||
}
|
||||
|
||||
$result = $this->db->sql_query($sql);
|
||||
$attempts = (int) $this->db->sql_fetchfield('attempts');
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
$attempt_data = array(
|
||||
'attempt_ip' => $this->user->ip,
|
||||
'attempt_browser' => trim(substr($this->user->browser, 0, 149)),
|
||||
'attempt_forwarded_for' => $this->user->forwarded_for,
|
||||
'attempt_time' => time(),
|
||||
'user_id' => ($row) ? (int) $row['user_id'] : 0,
|
||||
'username' => $username,
|
||||
'username_clean' => $username_clean,
|
||||
);
|
||||
$sql = 'INSERT INTO ' . LOGIN_ATTEMPT_TABLE . $this->db->sql_build_array('INSERT', $attempt_data);
|
||||
$this->db->sql_query($sql);
|
||||
}
|
||||
else
|
||||
{
|
||||
$attempts = 0;
|
||||
}
|
||||
|
||||
if (!$row)
|
||||
{
|
||||
if ($this->config['ip_login_limit_max'] && $attempts >= $this->config['ip_login_limit_max'])
|
||||
{
|
||||
return array(
|
||||
'status' => LOGIN_ERROR_ATTEMPTS,
|
||||
'error_msg' => 'LOGIN_ERROR_ATTEMPTS',
|
||||
'user_row' => array('user_id' => ANONYMOUS),
|
||||
);
|
||||
}
|
||||
|
||||
return array(
|
||||
'status' => LOGIN_ERROR_USERNAME,
|
||||
'error_msg' => 'LOGIN_ERROR_USERNAME',
|
||||
'user_row' => array('user_id' => ANONYMOUS),
|
||||
);
|
||||
}
|
||||
|
||||
$show_captcha = ($this->config['max_login_attempts'] && $row['user_login_attempts'] >= $this->config['max_login_attempts']) ||
|
||||
($this->config['ip_login_limit_max'] && $attempts >= $this->config['ip_login_limit_max']);
|
||||
|
||||
// If there are too many login attempts, we need to check for a confirm image
|
||||
// Every auth module is able to define what to do by itself...
|
||||
if ($show_captcha)
|
||||
{
|
||||
/* @var $captcha_factory \phpbb\captcha\factory */
|
||||
$captcha_factory = $this->phpbb_container->get('captcha.factory');
|
||||
$captcha = $captcha_factory->get_instance($this->config['captcha_plugin']);
|
||||
$captcha->init(CONFIRM_LOGIN);
|
||||
$vc_response = $captcha->validate($row);
|
||||
if ($vc_response)
|
||||
{
|
||||
return array(
|
||||
'status' => LOGIN_ERROR_ATTEMPTS,
|
||||
'error_msg' => 'LOGIN_ERROR_ATTEMPTS',
|
||||
'user_row' => $row,
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
$captcha->reset();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Check password ...
|
||||
if ($this->passwords_manager->check($password, $row['user_password'], $row))
|
||||
{
|
||||
// Check for old password hash...
|
||||
if ($this->passwords_manager->convert_flag || strlen($row['user_password']) == 32)
|
||||
{
|
||||
$hash = $this->passwords_manager->hash($password);
|
||||
|
||||
// Update the password in the users table to the new format
|
||||
$sql = 'UPDATE ' . USERS_TABLE . "
|
||||
SET user_password = '" . $this->db->sql_escape($hash) . "'
|
||||
WHERE user_id = {$row['user_id']}";
|
||||
$this->db->sql_query($sql);
|
||||
|
||||
$row['user_password'] = $hash;
|
||||
}
|
||||
|
||||
$sql = 'DELETE FROM ' . LOGIN_ATTEMPT_TABLE . '
|
||||
WHERE user_id = ' . $row['user_id'];
|
||||
$this->db->sql_query($sql);
|
||||
|
||||
if ($row['user_login_attempts'] != 0)
|
||||
{
|
||||
// Successful, reset login attempts (the user passed all stages)
|
||||
$sql = 'UPDATE ' . USERS_TABLE . '
|
||||
SET user_login_attempts = 0
|
||||
WHERE user_id = ' . $row['user_id'];
|
||||
$this->db->sql_query($sql);
|
||||
}
|
||||
|
||||
// User inactive...
|
||||
if ($row['user_type'] == USER_INACTIVE || $row['user_type'] == USER_IGNORE)
|
||||
{
|
||||
return array(
|
||||
'status' => LOGIN_ERROR_ACTIVE,
|
||||
'error_msg' => 'ACTIVE_ERROR',
|
||||
'user_row' => $row,
|
||||
);
|
||||
}
|
||||
|
||||
// Successful login... set user_login_attempts to zero...
|
||||
return array(
|
||||
'status' => LOGIN_SUCCESS,
|
||||
'error_msg' => false,
|
||||
'user_row' => $row,
|
||||
);
|
||||
}
|
||||
|
||||
// Password incorrect - increase login attempts
|
||||
$sql = 'UPDATE ' . USERS_TABLE . '
|
||||
SET user_login_attempts = user_login_attempts + 1
|
||||
WHERE user_id = ' . (int) $row['user_id'] . '
|
||||
AND user_login_attempts < ' . LOGIN_ATTEMPTS_MAX;
|
||||
$this->db->sql_query($sql);
|
||||
|
||||
// Give status about wrong password...
|
||||
return array(
|
||||
'status' => ($show_captcha) ? LOGIN_ERROR_ATTEMPTS : LOGIN_ERROR_PASSWORD,
|
||||
'error_msg' => 'LOGIN_ERROR_PASSWORD',
|
||||
'user_row' => $row,
|
||||
);
|
||||
}
|
||||
}
|
||||
10
phpbb/auth/provider/index.htm
Normal file
10
phpbb/auth/provider/index.htm
Normal file
@@ -0,0 +1,10 @@
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
</head>
|
||||
|
||||
<body bgcolor="#FFFFFF" text="#000000">
|
||||
|
||||
</body>
|
||||
</html>
|
||||
348
phpbb/auth/provider/ldap.php
Normal file
348
phpbb/auth/provider/ldap.php
Normal file
@@ -0,0 +1,348 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\auth\provider;
|
||||
|
||||
/**
|
||||
* Database authentication provider for phpBB3
|
||||
* This is for authentication via the integrated user table
|
||||
*/
|
||||
class ldap extends \phpbb\auth\provider\base
|
||||
{
|
||||
/**
|
||||
* phpBB passwords manager
|
||||
*
|
||||
* @var \phpbb\passwords\manager
|
||||
*/
|
||||
protected $passwords_manager;
|
||||
|
||||
/**
|
||||
* LDAP Authentication Constructor
|
||||
*
|
||||
* @param \phpbb\db\driver\driver_interface $db Database object
|
||||
* @param \phpbb\config\config $config Config object
|
||||
* @param \phpbb\passwords\manager $passwords_manager Passwords manager object
|
||||
* @param \phpbb\user $user User object
|
||||
*/
|
||||
public function __construct(\phpbb\db\driver\driver_interface $db, \phpbb\config\config $config, \phpbb\passwords\manager $passwords_manager, \phpbb\user $user)
|
||||
{
|
||||
$this->db = $db;
|
||||
$this->config = $config;
|
||||
$this->passwords_manager = $passwords_manager;
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
if (!@extension_loaded('ldap'))
|
||||
{
|
||||
return $this->user->lang['LDAP_NO_LDAP_EXTENSION'];
|
||||
}
|
||||
|
||||
$this->config['ldap_port'] = (int) $this->config['ldap_port'];
|
||||
if ($this->config['ldap_port'])
|
||||
{
|
||||
$ldap = @ldap_connect($this->config['ldap_server'], $this->config['ldap_port']);
|
||||
}
|
||||
else
|
||||
{
|
||||
$ldap = @ldap_connect($this->config['ldap_server']);
|
||||
}
|
||||
|
||||
if (!$ldap)
|
||||
{
|
||||
return $this->user->lang['LDAP_NO_SERVER_CONNECTION'];
|
||||
}
|
||||
|
||||
@ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, 3);
|
||||
@ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);
|
||||
|
||||
if ($this->config['ldap_user'] || $this->config['ldap_password'])
|
||||
{
|
||||
if (!@ldap_bind($ldap, htmlspecialchars_decode($this->config['ldap_user']), htmlspecialchars_decode($this->config['ldap_password'])))
|
||||
{
|
||||
return $this->user->lang['LDAP_INCORRECT_USER_PASSWORD'];
|
||||
}
|
||||
}
|
||||
|
||||
// ldap_connect only checks whether the specified server is valid, so the connection might still fail
|
||||
$search = @ldap_search(
|
||||
$ldap,
|
||||
htmlspecialchars_decode($this->config['ldap_base_dn']),
|
||||
$this->ldap_user_filter($this->user->data['username']),
|
||||
(empty($this->config['ldap_email'])) ?
|
||||
array(htmlspecialchars_decode($this->config['ldap_uid'])) :
|
||||
array(htmlspecialchars_decode($this->config['ldap_uid']), htmlspecialchars_decode($this->config['ldap_email'])),
|
||||
0,
|
||||
1
|
||||
);
|
||||
|
||||
if ($search === false)
|
||||
{
|
||||
return $this->user->lang['LDAP_SEARCH_FAILED'];
|
||||
}
|
||||
|
||||
$result = @ldap_get_entries($ldap, $search);
|
||||
|
||||
@ldap_close($ldap);
|
||||
|
||||
if (!is_array($result) || count($result) < 2)
|
||||
{
|
||||
return sprintf($this->user->lang['LDAP_NO_IDENTITY'], $this->user->data['username']);
|
||||
}
|
||||
|
||||
if (!empty($this->config['ldap_email']) && !isset($result[0][htmlspecialchars_decode($this->config['ldap_email'])]))
|
||||
{
|
||||
return $this->user->lang['LDAP_NO_EMAIL'];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function login($username, $password)
|
||||
{
|
||||
// do not allow empty password
|
||||
if (!$password)
|
||||
{
|
||||
return array(
|
||||
'status' => LOGIN_ERROR_PASSWORD,
|
||||
'error_msg' => 'NO_PASSWORD_SUPPLIED',
|
||||
'user_row' => array('user_id' => ANONYMOUS),
|
||||
);
|
||||
}
|
||||
|
||||
if (!$username)
|
||||
{
|
||||
return array(
|
||||
'status' => LOGIN_ERROR_USERNAME,
|
||||
'error_msg' => 'LOGIN_ERROR_USERNAME',
|
||||
'user_row' => array('user_id' => ANONYMOUS),
|
||||
);
|
||||
}
|
||||
|
||||
if (!@extension_loaded('ldap'))
|
||||
{
|
||||
return array(
|
||||
'status' => LOGIN_ERROR_EXTERNAL_AUTH,
|
||||
'error_msg' => 'LDAP_NO_LDAP_EXTENSION',
|
||||
'user_row' => array('user_id' => ANONYMOUS),
|
||||
);
|
||||
}
|
||||
|
||||
$this->config['ldap_port'] = (int) $this->config['ldap_port'];
|
||||
if ($this->config['ldap_port'])
|
||||
{
|
||||
$ldap = @ldap_connect($this->config['ldap_server'], $this->config['ldap_port']);
|
||||
}
|
||||
else
|
||||
{
|
||||
$ldap = @ldap_connect($this->config['ldap_server']);
|
||||
}
|
||||
|
||||
if (!$ldap)
|
||||
{
|
||||
return array(
|
||||
'status' => LOGIN_ERROR_EXTERNAL_AUTH,
|
||||
'error_msg' => 'LDAP_NO_SERVER_CONNECTION',
|
||||
'user_row' => array('user_id' => ANONYMOUS),
|
||||
);
|
||||
}
|
||||
|
||||
@ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, 3);
|
||||
@ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);
|
||||
|
||||
if ($this->config['ldap_user'] || $this->config['ldap_password'])
|
||||
{
|
||||
if (!@ldap_bind($ldap, htmlspecialchars_decode($this->config['ldap_user']), htmlspecialchars_decode($this->config['ldap_password'])))
|
||||
{
|
||||
return array(
|
||||
'status' => LOGIN_ERROR_EXTERNAL_AUTH,
|
||||
'error_msg' => 'LDAP_NO_SERVER_CONNECTION',
|
||||
'user_row' => array('user_id' => ANONYMOUS),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$search = @ldap_search(
|
||||
$ldap,
|
||||
htmlspecialchars_decode($this->config['ldap_base_dn']),
|
||||
$this->ldap_user_filter($username),
|
||||
(empty($this->config['ldap_email'])) ?
|
||||
array(htmlspecialchars_decode($this->config['ldap_uid'])) :
|
||||
array(htmlspecialchars_decode($this->config['ldap_uid']), htmlspecialchars_decode($this->config['ldap_email'])),
|
||||
0,
|
||||
1
|
||||
);
|
||||
|
||||
$ldap_result = @ldap_get_entries($ldap, $search);
|
||||
|
||||
if (is_array($ldap_result) && count($ldap_result) > 1)
|
||||
{
|
||||
if (@ldap_bind($ldap, $ldap_result[0]['dn'], htmlspecialchars_decode($password)))
|
||||
{
|
||||
@ldap_close($ldap);
|
||||
|
||||
$sql ='SELECT user_id, username, user_password, user_passchg, user_email, user_type
|
||||
FROM ' . USERS_TABLE . "
|
||||
WHERE username_clean = '" . $this->db->sql_escape(utf8_clean_string($username)) . "'";
|
||||
$result = $this->db->sql_query($sql);
|
||||
$row = $this->db->sql_fetchrow($result);
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
if ($row)
|
||||
{
|
||||
unset($ldap_result);
|
||||
|
||||
// User inactive...
|
||||
if ($row['user_type'] == USER_INACTIVE || $row['user_type'] == USER_IGNORE)
|
||||
{
|
||||
return array(
|
||||
'status' => LOGIN_ERROR_ACTIVE,
|
||||
'error_msg' => 'ACTIVE_ERROR',
|
||||
'user_row' => $row,
|
||||
);
|
||||
}
|
||||
|
||||
// Successful login... set user_login_attempts to zero...
|
||||
return array(
|
||||
'status' => LOGIN_SUCCESS,
|
||||
'error_msg' => false,
|
||||
'user_row' => $row,
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
// retrieve default group id
|
||||
$sql = 'SELECT group_id
|
||||
FROM ' . GROUPS_TABLE . "
|
||||
WHERE group_name = '" . $this->db->sql_escape('REGISTERED') . "'
|
||||
AND group_type = " . GROUP_SPECIAL;
|
||||
$result = $this->db->sql_query($sql);
|
||||
$row = $this->db->sql_fetchrow($result);
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
if (!$row)
|
||||
{
|
||||
trigger_error('NO_GROUP');
|
||||
}
|
||||
|
||||
// generate user account data
|
||||
$ldap_user_row = array(
|
||||
'username' => $username,
|
||||
'user_password' => $this->passwords_manager->hash($password),
|
||||
'user_email' => (!empty($this->config['ldap_email'])) ? utf8_htmlspecialchars($ldap_result[0][htmlspecialchars_decode($this->config['ldap_email'])][0]) : '',
|
||||
'group_id' => (int) $row['group_id'],
|
||||
'user_type' => USER_NORMAL,
|
||||
'user_ip' => $this->user->ip,
|
||||
'user_new' => ($this->config['new_member_post_limit']) ? 1 : 0,
|
||||
);
|
||||
|
||||
unset($ldap_result);
|
||||
|
||||
// this is the user's first login so create an empty profile
|
||||
return array(
|
||||
'status' => LOGIN_SUCCESS_CREATE_PROFILE,
|
||||
'error_msg' => false,
|
||||
'user_row' => $ldap_user_row,
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
unset($ldap_result);
|
||||
@ldap_close($ldap);
|
||||
|
||||
// Give status about wrong password...
|
||||
return array(
|
||||
'status' => LOGIN_ERROR_PASSWORD,
|
||||
'error_msg' => 'LOGIN_ERROR_PASSWORD',
|
||||
'user_row' => array('user_id' => ANONYMOUS),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ldap_close($ldap);
|
||||
|
||||
return array(
|
||||
'status' => LOGIN_ERROR_USERNAME,
|
||||
'error_msg' => 'LOGIN_ERROR_USERNAME',
|
||||
'user_row' => array('user_id' => ANONYMOUS),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function acp()
|
||||
{
|
||||
// These are fields required in the config table
|
||||
return array(
|
||||
'ldap_server', 'ldap_port', 'ldap_base_dn', 'ldap_uid', 'ldap_user_filter', 'ldap_email', 'ldap_user', 'ldap_password',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get_acp_template($new_config)
|
||||
{
|
||||
return array(
|
||||
'TEMPLATE_FILE' => 'auth_provider_ldap.html',
|
||||
'TEMPLATE_VARS' => array(
|
||||
'AUTH_LDAP_BASE_DN' => $new_config['ldap_base_dn'],
|
||||
'AUTH_LDAP_EMAIL' => $new_config['ldap_email'],
|
||||
'AUTH_LDAP_PASSORD' => $new_config['ldap_password'] !== '' ? '********' : '',
|
||||
'AUTH_LDAP_PORT' => $new_config['ldap_port'],
|
||||
'AUTH_LDAP_SERVER' => $new_config['ldap_server'],
|
||||
'AUTH_LDAP_UID' => $new_config['ldap_uid'],
|
||||
'AUTH_LDAP_USER' => $new_config['ldap_user'],
|
||||
'AUTH_LDAP_USER_FILTER' => $new_config['ldap_user_filter'],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a filter string for ldap_search to find a user
|
||||
*
|
||||
* @param $username string Username identifying the searched user
|
||||
*
|
||||
* @return string A filter string for ldap_search
|
||||
*/
|
||||
private function ldap_user_filter($username)
|
||||
{
|
||||
$filter = '(' . $this->config['ldap_uid'] . '=' . $this->ldap_escape(htmlspecialchars_decode($username)) . ')';
|
||||
if ($this->config['ldap_user_filter'])
|
||||
{
|
||||
$_filter = ($this->config['ldap_user_filter'][0] == '(' && substr($this->config['ldap_user_filter'], -1) == ')') ? $this->config['ldap_user_filter'] : "({$this->config['ldap_user_filter']})";
|
||||
$filter = "(&{$filter}{$_filter})";
|
||||
}
|
||||
return $filter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Escapes an LDAP AttributeValue
|
||||
*
|
||||
* @param string $string The string to be escaped
|
||||
* @return string The escaped string
|
||||
*/
|
||||
private function ldap_escape($string)
|
||||
{
|
||||
return str_replace(array('*', '\\', '(', ')'), array('\\*', '\\\\', '\\(', '\\)'), $string);
|
||||
}
|
||||
}
|
||||
747
phpbb/auth/provider/oauth/oauth.php
Normal file
747
phpbb/auth/provider/oauth/oauth.php
Normal file
@@ -0,0 +1,747 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\auth\provider\oauth;
|
||||
|
||||
use OAuth\Common\Consumer\Credentials;
|
||||
|
||||
/**
|
||||
* OAuth authentication provider for phpBB3
|
||||
*/
|
||||
class oauth extends \phpbb\auth\provider\base
|
||||
{
|
||||
/**
|
||||
* Database driver
|
||||
*
|
||||
* @var \phpbb\db\driver\driver_interface
|
||||
*/
|
||||
protected $db;
|
||||
|
||||
/**
|
||||
* phpBB config
|
||||
*
|
||||
* @var \phpbb\config\config
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* phpBB passwords manager
|
||||
*
|
||||
* @var \phpbb\passwords\manager
|
||||
*/
|
||||
protected $passwords_manager;
|
||||
|
||||
/**
|
||||
* phpBB request object
|
||||
*
|
||||
* @var \phpbb\request\request_interface
|
||||
*/
|
||||
protected $request;
|
||||
|
||||
/**
|
||||
* phpBB user
|
||||
*
|
||||
* @var \phpbb\user
|
||||
*/
|
||||
protected $user;
|
||||
|
||||
/**
|
||||
* OAuth token table
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $auth_provider_oauth_token_storage_table;
|
||||
|
||||
/**
|
||||
* OAuth state table
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $auth_provider_oauth_state_table;
|
||||
|
||||
/**
|
||||
* OAuth account association table
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $auth_provider_oauth_token_account_assoc;
|
||||
|
||||
/**
|
||||
* All OAuth service providers
|
||||
*
|
||||
* @var \phpbb\di\service_collection Contains \phpbb\auth\provider\oauth\service_interface
|
||||
*/
|
||||
protected $service_providers;
|
||||
|
||||
/**
|
||||
* Users table
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $users_table;
|
||||
|
||||
/**
|
||||
* Cached current uri object
|
||||
*
|
||||
* @var \OAuth\Common\Http\Uri\UriInterface|null
|
||||
*/
|
||||
protected $current_uri;
|
||||
|
||||
/**
|
||||
* DI container
|
||||
*
|
||||
* @var \Symfony\Component\DependencyInjection\ContainerInterface
|
||||
*/
|
||||
protected $phpbb_container;
|
||||
|
||||
/**
|
||||
* phpBB event dispatcher
|
||||
*
|
||||
* @var \phpbb\event\dispatcher_interface
|
||||
*/
|
||||
protected $dispatcher;
|
||||
|
||||
/**
|
||||
* phpBB root path
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $phpbb_root_path;
|
||||
|
||||
/**
|
||||
* PHP file extension
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $php_ext;
|
||||
|
||||
/**
|
||||
* OAuth Authentication Constructor
|
||||
*
|
||||
* @param \phpbb\db\driver\driver_interface $db
|
||||
* @param \phpbb\config\config $config
|
||||
* @param \phpbb\passwords\manager $passwords_manager
|
||||
* @param \phpbb\request\request_interface $request
|
||||
* @param \phpbb\user $user
|
||||
* @param string $auth_provider_oauth_token_storage_table
|
||||
* @param string $auth_provider_oauth_state_table
|
||||
* @param string $auth_provider_oauth_token_account_assoc
|
||||
* @param \phpbb\di\service_collection $service_providers Contains \phpbb\auth\provider\oauth\service_interface
|
||||
* @param string $users_table
|
||||
* @param \Symfony\Component\DependencyInjection\ContainerInterface $phpbb_container DI container
|
||||
* @param \phpbb\event\dispatcher_interface $dispatcher phpBB event dispatcher
|
||||
* @param string $phpbb_root_path
|
||||
* @param string $php_ext
|
||||
*/
|
||||
public function __construct(\phpbb\db\driver\driver_interface $db, \phpbb\config\config $config, \phpbb\passwords\manager $passwords_manager, \phpbb\request\request_interface $request, \phpbb\user $user, $auth_provider_oauth_token_storage_table, $auth_provider_oauth_state_table, $auth_provider_oauth_token_account_assoc, \phpbb\di\service_collection $service_providers, $users_table, \Symfony\Component\DependencyInjection\ContainerInterface $phpbb_container, \phpbb\event\dispatcher_interface $dispatcher, $phpbb_root_path, $php_ext)
|
||||
{
|
||||
$this->db = $db;
|
||||
$this->config = $config;
|
||||
$this->passwords_manager = $passwords_manager;
|
||||
$this->request = $request;
|
||||
$this->user = $user;
|
||||
$this->auth_provider_oauth_token_storage_table = $auth_provider_oauth_token_storage_table;
|
||||
$this->auth_provider_oauth_state_table = $auth_provider_oauth_state_table;
|
||||
$this->auth_provider_oauth_token_account_assoc = $auth_provider_oauth_token_account_assoc;
|
||||
$this->service_providers = $service_providers;
|
||||
$this->users_table = $users_table;
|
||||
$this->phpbb_container = $phpbb_container;
|
||||
$this->dispatcher = $dispatcher;
|
||||
$this->phpbb_root_path = $phpbb_root_path;
|
||||
$this->php_ext = $php_ext;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
// This does not test whether or not the key and secret provided are valid.
|
||||
foreach ($this->service_providers as $service_provider)
|
||||
{
|
||||
$credentials = $service_provider->get_service_credentials();
|
||||
|
||||
if (($credentials['key'] && !$credentials['secret']) || (!$credentials['key'] && $credentials['secret']))
|
||||
{
|
||||
return $this->user->lang['AUTH_PROVIDER_OAUTH_ERROR_ELEMENT_MISSING'];
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function login($username, $password)
|
||||
{
|
||||
// Temporary workaround for only having one authentication provider available
|
||||
if (!$this->request->is_set('oauth_service'))
|
||||
{
|
||||
$provider = new \phpbb\auth\provider\db($this->db, $this->config, $this->passwords_manager, $this->request, $this->user, $this->phpbb_container, $this->phpbb_root_path, $this->php_ext);
|
||||
return $provider->login($username, $password);
|
||||
}
|
||||
|
||||
// Request the name of the OAuth service
|
||||
$service_name_original = $this->request->variable('oauth_service', '', false);
|
||||
$service_name = 'auth.provider.oauth.service.' . strtolower($service_name_original);
|
||||
if ($service_name_original === '' || !array_key_exists($service_name, $this->service_providers))
|
||||
{
|
||||
return array(
|
||||
'status' => LOGIN_ERROR_EXTERNAL_AUTH,
|
||||
'error_msg' => 'LOGIN_ERROR_OAUTH_SERVICE_DOES_NOT_EXIST',
|
||||
'user_row' => array('user_id' => ANONYMOUS),
|
||||
);
|
||||
}
|
||||
|
||||
// Get the service credentials for the given service
|
||||
$service_credentials = $this->service_providers[$service_name]->get_service_credentials();
|
||||
|
||||
$storage = new \phpbb\auth\provider\oauth\token_storage($this->db, $this->user, $this->auth_provider_oauth_token_storage_table, $this->auth_provider_oauth_state_table);
|
||||
$query = 'mode=login&login=external&oauth_service=' . $service_name_original;
|
||||
$service = $this->get_service($service_name_original, $storage, $service_credentials, $query, $this->service_providers[$service_name]->get_auth_scope());
|
||||
|
||||
if (($service::OAUTH_VERSION === 2 && $this->request->is_set('code', \phpbb\request\request_interface::GET))
|
||||
|| ($service::OAUTH_VERSION === 1 && $this->request->is_set('oauth_token', \phpbb\request\request_interface::GET)))
|
||||
{
|
||||
$this->service_providers[$service_name]->set_external_service_provider($service);
|
||||
$unique_id = $this->service_providers[$service_name]->perform_auth_login();
|
||||
|
||||
// Check to see if this provider is already assosciated with an account
|
||||
$data = array(
|
||||
'provider' => $service_name_original,
|
||||
'oauth_provider_id' => $unique_id
|
||||
);
|
||||
|
||||
$sql = 'SELECT user_id FROM ' . $this->auth_provider_oauth_token_account_assoc . '
|
||||
WHERE ' . $this->db->sql_build_array('SELECT', $data);
|
||||
$result = $this->db->sql_query($sql);
|
||||
$row = $this->db->sql_fetchrow($result);
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
$redirect_data = array(
|
||||
'auth_provider' => 'oauth',
|
||||
'login_link_oauth_service' => $service_name_original,
|
||||
);
|
||||
|
||||
/**
|
||||
* Event is triggered before check if provider is already associated with an account
|
||||
*
|
||||
* @event core.oauth_login_after_check_if_provider_id_has_match
|
||||
* @var array row User row
|
||||
* @var array data Provider data
|
||||
* @var array redirect_data Data to be appended to the redirect url
|
||||
* @var \OAuth\Common\Service\ServiceInterface service OAuth service
|
||||
* @since 3.2.3-RC1
|
||||
* @changed 3.2.6-RC1 Added redirect_data
|
||||
*/
|
||||
$vars = array(
|
||||
'row',
|
||||
'data',
|
||||
'redirect_data',
|
||||
'service',
|
||||
);
|
||||
extract($this->dispatcher->trigger_event('core.oauth_login_after_check_if_provider_id_has_match', compact($vars)));
|
||||
|
||||
if (!$row)
|
||||
{
|
||||
// The user does not yet exist, ask to link or create profile
|
||||
return array(
|
||||
'status' => LOGIN_SUCCESS_LINK_PROFILE,
|
||||
'error_msg' => 'LOGIN_OAUTH_ACCOUNT_NOT_LINKED',
|
||||
'user_row' => array(),
|
||||
'redirect_data' => $redirect_data,
|
||||
);
|
||||
}
|
||||
|
||||
// Retrieve the user's account
|
||||
$sql = 'SELECT user_id, username, user_password, user_passchg, user_email, user_type, user_login_attempts
|
||||
FROM ' . $this->users_table . '
|
||||
WHERE user_id = ' . (int) $row['user_id'];
|
||||
$result = $this->db->sql_query($sql);
|
||||
$row = $this->db->sql_fetchrow($result);
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
if (!$row)
|
||||
{
|
||||
throw new \Exception('AUTH_PROVIDER_OAUTH_ERROR_INVALID_ENTRY');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the user is banned.
|
||||
* The fourth parameter, return, has to be true,
|
||||
* otherwise the OAuth login is still called and
|
||||
* an uncaught exception is thrown as there is no
|
||||
* token stored in the database.
|
||||
*/
|
||||
$ban = $this->user->check_ban($row['user_id'], $row['user_ip'], $row['user_email'], true);
|
||||
if (!empty($ban))
|
||||
{
|
||||
$till_date = !empty($ban['ban_end']) ? $this->user->format_date($ban['ban_end']) : '';
|
||||
$message = !empty($ban['ban_end']) ? 'BOARD_BAN_TIME' : 'BOARD_BAN_PERM';
|
||||
|
||||
$contact_link = phpbb_get_board_contact_link($this->config, $this->phpbb_root_path, $this->php_ext);
|
||||
$message = $this->user->lang($message, $till_date, '<a href="' . $contact_link . '">', '</a>');
|
||||
$message .= !empty($ban['ban_give_reason']) ? '<br /><br />' . $this->user->lang('BOARD_BAN_REASON', $ban['ban_give_reason']) : '';
|
||||
$message .= !empty($ban['ban_triggered_by']) ? '<br /><br /><em>' . $this->user->lang('BAN_TRIGGERED_BY_' . strtoupper($ban['ban_triggered_by'])) . '</em>' : '';
|
||||
|
||||
return array(
|
||||
'status' => LOGIN_BREAK,
|
||||
'error_msg' => $message,
|
||||
'user_row' => $row,
|
||||
);
|
||||
}
|
||||
|
||||
// Update token storage to store the user_id
|
||||
$storage->set_user_id($row['user_id']);
|
||||
|
||||
/**
|
||||
* Event is triggered after user is successfully logged in via OAuth.
|
||||
*
|
||||
* @event core.auth_oauth_login_after
|
||||
* @var array row User row
|
||||
* @since 3.1.11-RC1
|
||||
*/
|
||||
$vars = array(
|
||||
'row',
|
||||
);
|
||||
extract($this->dispatcher->trigger_event('core.auth_oauth_login_after', compact($vars)));
|
||||
|
||||
// The user is now authenticated and can be logged in
|
||||
return array(
|
||||
'status' => LOGIN_SUCCESS,
|
||||
'error_msg' => false,
|
||||
'user_row' => $row,
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($service::OAUTH_VERSION === 1)
|
||||
{
|
||||
$token = $service->requestRequestToken();
|
||||
$url = $service->getAuthorizationUri(array('oauth_token' => $token->getRequestToken()));
|
||||
}
|
||||
else
|
||||
{
|
||||
$url = $service->getAuthorizationUri();
|
||||
}
|
||||
header('Location: ' . $url);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the cached current_uri object or creates and caches it if it is
|
||||
* not already created. In each case the query string is updated based on
|
||||
* the $query parameter.
|
||||
*
|
||||
* @param string $service_name The name of the service
|
||||
* @param string $query The query string of the current_uri
|
||||
* used in redirects
|
||||
* @return \OAuth\Common\Http\Uri\UriInterface
|
||||
*/
|
||||
protected function get_current_uri($service_name, $query)
|
||||
{
|
||||
if ($this->current_uri)
|
||||
{
|
||||
$this->current_uri->setQuery($query);
|
||||
return $this->current_uri;
|
||||
}
|
||||
|
||||
$uri_factory = new \OAuth\Common\Http\Uri\UriFactory();
|
||||
$super_globals = $this->request->get_super_global(\phpbb\request\request_interface::SERVER);
|
||||
if (!empty($super_globals['HTTP_X_FORWARDED_PROTO']) && $super_globals['HTTP_X_FORWARDED_PROTO'] === 'https')
|
||||
{
|
||||
$super_globals['HTTPS'] = 'on';
|
||||
$super_globals['SERVER_PORT'] = 443;
|
||||
}
|
||||
$current_uri = $uri_factory->createFromSuperGlobalArray($super_globals);
|
||||
$current_uri->setQuery($query);
|
||||
|
||||
$this->current_uri = $current_uri;
|
||||
return $current_uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new service object
|
||||
*
|
||||
* @param string $service_name The name of the service
|
||||
* @param \phpbb\auth\provider\oauth\token_storage $storage
|
||||
* @param array $service_credentials {@see \phpbb\auth\provider\oauth\oauth::get_service_credentials}
|
||||
* @param string $query The query string of the
|
||||
* current_uri used in redirection
|
||||
* @param array $scopes The scope of the request against
|
||||
* the api.
|
||||
* @return \OAuth\Common\Service\ServiceInterface
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function get_service($service_name, \phpbb\auth\provider\oauth\token_storage $storage, array $service_credentials, $query, array $scopes = array())
|
||||
{
|
||||
$current_uri = $this->get_current_uri($service_name, $query);
|
||||
|
||||
// Setup the credentials for the requests
|
||||
$credentials = new Credentials(
|
||||
$service_credentials['key'],
|
||||
$service_credentials['secret'],
|
||||
$current_uri->getAbsoluteUri()
|
||||
);
|
||||
|
||||
$service_factory = new \OAuth\ServiceFactory();
|
||||
$service = $service_factory->createService($service_name, $credentials, $storage, $scopes);
|
||||
|
||||
if (!$service)
|
||||
{
|
||||
throw new \Exception('AUTH_PROVIDER_OAUTH_ERROR_SERVICE_NOT_CREATED');
|
||||
}
|
||||
|
||||
return $service;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get_login_data()
|
||||
{
|
||||
$login_data = array(
|
||||
'TEMPLATE_FILE' => 'login_body_oauth.html',
|
||||
'BLOCK_VAR_NAME' => 'oauth',
|
||||
'BLOCK_VARS' => array(),
|
||||
);
|
||||
|
||||
foreach ($this->service_providers as $service_name => $service_provider)
|
||||
{
|
||||
// Only include data if the credentials are set
|
||||
$credentials = $service_provider->get_service_credentials();
|
||||
if ($credentials['key'] && $credentials['secret'])
|
||||
{
|
||||
$actual_name = str_replace('auth.provider.oauth.service.', '', $service_name);
|
||||
$redirect_url = build_url(false) . '&login=external&oauth_service=' . $actual_name;
|
||||
$login_data['BLOCK_VARS'][$service_name] = array(
|
||||
'REDIRECT_URL' => redirect($redirect_url, true),
|
||||
'SERVICE_NAME' => $this->user->lang['AUTH_PROVIDER_OAUTH_SERVICE_' . strtoupper($actual_name)],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $login_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function acp()
|
||||
{
|
||||
$ret = array();
|
||||
|
||||
foreach ($this->service_providers as $service_name => $service_provider)
|
||||
{
|
||||
$actual_name = str_replace('auth.provider.oauth.service.', '', $service_name);
|
||||
$ret[] = 'auth_oauth_' . $actual_name . '_key';
|
||||
$ret[] = 'auth_oauth_' . $actual_name . '_secret';
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get_acp_template($new_config)
|
||||
{
|
||||
$ret = array(
|
||||
'BLOCK_VAR_NAME' => 'oauth_services',
|
||||
'BLOCK_VARS' => array(),
|
||||
'TEMPLATE_FILE' => 'auth_provider_oauth.html',
|
||||
'TEMPLATE_VARS' => array(),
|
||||
);
|
||||
|
||||
foreach ($this->service_providers as $service_name => $service_provider)
|
||||
{
|
||||
$actual_name = str_replace('auth.provider.oauth.service.', '', $service_name);
|
||||
$ret['BLOCK_VARS'][$actual_name] = array(
|
||||
'ACTUAL_NAME' => $this->user->lang['AUTH_PROVIDER_OAUTH_SERVICE_' . strtoupper($actual_name)],
|
||||
'KEY' => $new_config['auth_oauth_' . $actual_name . '_key'],
|
||||
'NAME' => $actual_name,
|
||||
'SECRET' => $new_config['auth_oauth_' . $actual_name . '_secret'],
|
||||
);
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function login_link_has_necessary_data($login_link_data)
|
||||
{
|
||||
if (empty($login_link_data))
|
||||
{
|
||||
return 'LOGIN_LINK_NO_DATA_PROVIDED';
|
||||
}
|
||||
|
||||
if (!array_key_exists('oauth_service', $login_link_data) || !$login_link_data['oauth_service'] ||
|
||||
!array_key_exists('link_method', $login_link_data) || !$login_link_data['link_method'])
|
||||
{
|
||||
return 'LOGIN_LINK_MISSING_DATA';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function link_account(array $link_data)
|
||||
{
|
||||
// Check for a valid link method (auth_link or login_link)
|
||||
if (!array_key_exists('link_method', $link_data) ||
|
||||
!in_array($link_data['link_method'], array(
|
||||
'auth_link',
|
||||
'login_link',
|
||||
)))
|
||||
{
|
||||
return 'LOGIN_LINK_MISSING_DATA';
|
||||
}
|
||||
|
||||
// We must have an oauth_service listed, check for it two ways
|
||||
if (!array_key_exists('oauth_service', $link_data) || !$link_data['oauth_service'])
|
||||
{
|
||||
$link_data['oauth_service'] = $this->request->variable('oauth_service', '');
|
||||
|
||||
if (!$link_data['oauth_service'])
|
||||
{
|
||||
return 'LOGIN_LINK_MISSING_DATA';
|
||||
}
|
||||
}
|
||||
|
||||
$service_name = 'auth.provider.oauth.service.' . strtolower($link_data['oauth_service']);
|
||||
if (!array_key_exists($service_name, $this->service_providers))
|
||||
{
|
||||
return 'LOGIN_ERROR_OAUTH_SERVICE_DOES_NOT_EXIST';
|
||||
}
|
||||
|
||||
switch ($link_data['link_method'])
|
||||
{
|
||||
case 'auth_link':
|
||||
return $this->link_account_auth_link($link_data, $service_name);
|
||||
case 'login_link':
|
||||
return $this->link_account_login_link($link_data, $service_name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the account linking for login_link
|
||||
*
|
||||
* @param array $link_data The same variable given to {@see \phpbb\auth\provider\provider_interface::link_account}
|
||||
* @param string $service_name The name of the service being used in
|
||||
* linking.
|
||||
* @return string|null Returns a language constant (string) if an error is
|
||||
* encountered, or null on success.
|
||||
*/
|
||||
protected function link_account_login_link(array $link_data, $service_name)
|
||||
{
|
||||
$storage = new \phpbb\auth\provider\oauth\token_storage($this->db, $this->user, $this->auth_provider_oauth_token_storage_table, $this->auth_provider_oauth_state_table);
|
||||
|
||||
// Check for an access token, they should have one
|
||||
if (!$storage->has_access_token_by_session($service_name))
|
||||
{
|
||||
return 'LOGIN_LINK_ERROR_OAUTH_NO_ACCESS_TOKEN';
|
||||
}
|
||||
|
||||
// Prepare the query string
|
||||
$query = 'mode=login_link&login_link_oauth_service=' . strtolower($link_data['oauth_service']);
|
||||
|
||||
// Prepare for an authentication request
|
||||
$service_credentials = $this->service_providers[$service_name]->get_service_credentials();
|
||||
$scopes = $this->service_providers[$service_name]->get_auth_scope();
|
||||
$service = $this->get_service(strtolower($link_data['oauth_service']), $storage, $service_credentials, $query, $scopes);
|
||||
$this->service_providers[$service_name]->set_external_service_provider($service);
|
||||
|
||||
// The user has already authenticated successfully, request to authenticate again
|
||||
$unique_id = $this->service_providers[$service_name]->perform_token_auth();
|
||||
|
||||
// Insert into table, they will be able to log in after this
|
||||
$data = array(
|
||||
'user_id' => $link_data['user_id'],
|
||||
'provider' => strtolower($link_data['oauth_service']),
|
||||
'oauth_provider_id' => $unique_id,
|
||||
);
|
||||
|
||||
$this->link_account_perform_link($data);
|
||||
// Update token storage to store the user_id
|
||||
$storage->set_user_id($link_data['user_id']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the account linking for auth_link
|
||||
*
|
||||
* @param array $link_data The same variable given to {@see \phpbb\auth\provider\provider_interface::link_account}
|
||||
* @param string $service_name The name of the service being used in
|
||||
* linking.
|
||||
* @return string|null Returns a language constant (string) if an error is
|
||||
* encountered, or null on success.
|
||||
*/
|
||||
protected function link_account_auth_link(array $link_data, $service_name)
|
||||
{
|
||||
$storage = new \phpbb\auth\provider\oauth\token_storage($this->db, $this->user, $this->auth_provider_oauth_token_storage_table, $this->auth_provider_oauth_state_table);
|
||||
$query = 'i=ucp_auth_link&mode=auth_link&link=1&oauth_service=' . strtolower($link_data['oauth_service']);
|
||||
$service_credentials = $this->service_providers[$service_name]->get_service_credentials();
|
||||
$scopes = $this->service_providers[$service_name]->get_auth_scope();
|
||||
$service = $this->get_service(strtolower($link_data['oauth_service']), $storage, $service_credentials, $query, $scopes);
|
||||
|
||||
if (($service::OAUTH_VERSION === 2 && $this->request->is_set('code', \phpbb\request\request_interface::GET))
|
||||
|| ($service::OAUTH_VERSION === 1 && $this->request->is_set('oauth_token', \phpbb\request\request_interface::GET)))
|
||||
{
|
||||
$this->service_providers[$service_name]->set_external_service_provider($service);
|
||||
$unique_id = $this->service_providers[$service_name]->perform_auth_login();
|
||||
|
||||
// Insert into table, they will be able to log in after this
|
||||
$data = array(
|
||||
'user_id' => $this->user->data['user_id'],
|
||||
'provider' => strtolower($link_data['oauth_service']),
|
||||
'oauth_provider_id' => $unique_id,
|
||||
);
|
||||
|
||||
$this->link_account_perform_link($data);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($service::OAUTH_VERSION === 1)
|
||||
{
|
||||
$token = $service->requestRequestToken();
|
||||
$url = $service->getAuthorizationUri(array('oauth_token' => $token->getRequestToken()));
|
||||
}
|
||||
else
|
||||
{
|
||||
$url = $service->getAuthorizationUri();
|
||||
}
|
||||
header('Location: ' . $url);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the query that inserts an account link
|
||||
*
|
||||
* @param array $data This array is passed to db->sql_build_array
|
||||
*/
|
||||
protected function link_account_perform_link(array $data)
|
||||
{
|
||||
$sql = 'INSERT INTO ' . $this->auth_provider_oauth_token_account_assoc . '
|
||||
' . $this->db->sql_build_array('INSERT', $data);
|
||||
$this->db->sql_query($sql);
|
||||
|
||||
/**
|
||||
* Event is triggered after user links account.
|
||||
*
|
||||
* @event core.auth_oauth_link_after
|
||||
* @var array data User row
|
||||
* @since 3.1.11-RC1
|
||||
*/
|
||||
$vars = array(
|
||||
'data',
|
||||
);
|
||||
extract($this->dispatcher->trigger_event('core.auth_oauth_link_after', compact($vars)));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function logout($data, $new_session)
|
||||
{
|
||||
// Clear all tokens belonging to the user
|
||||
$storage = new \phpbb\auth\provider\oauth\token_storage($this->db, $this->user, $this->auth_provider_oauth_token_storage_table, $this->auth_provider_oauth_state_table);
|
||||
$storage->clearAllTokens();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get_auth_link_data($user_id = 0)
|
||||
{
|
||||
$block_vars = array();
|
||||
|
||||
// Get all external accounts tied to the current user
|
||||
$data = array(
|
||||
'user_id' => ($user_id <= 0) ? (int) $this->user->data['user_id'] : (int) $user_id,
|
||||
);
|
||||
$sql = 'SELECT oauth_provider_id, provider FROM ' . $this->auth_provider_oauth_token_account_assoc . '
|
||||
WHERE ' . $this->db->sql_build_array('SELECT', $data);
|
||||
$result = $this->db->sql_query($sql);
|
||||
$rows = $this->db->sql_fetchrowset($result);
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
$oauth_user_ids = array();
|
||||
|
||||
if ($rows !== false && count($rows))
|
||||
{
|
||||
foreach ($rows as $row)
|
||||
{
|
||||
$oauth_user_ids[$row['provider']] = $row['oauth_provider_id'];
|
||||
}
|
||||
}
|
||||
unset($rows);
|
||||
|
||||
foreach ($this->service_providers as $service_name => $service_provider)
|
||||
{
|
||||
// Only include data if the credentials are set
|
||||
$credentials = $service_provider->get_service_credentials();
|
||||
if ($credentials['key'] && $credentials['secret'])
|
||||
{
|
||||
$actual_name = str_replace('auth.provider.oauth.service.', '', $service_name);
|
||||
|
||||
$block_vars[$service_name] = array(
|
||||
'HIDDEN_FIELDS' => array(
|
||||
'link' => (!isset($oauth_user_ids[$actual_name])),
|
||||
'oauth_service' => $actual_name,
|
||||
),
|
||||
|
||||
'SERVICE_ID' => $actual_name,
|
||||
'SERVICE_NAME' => $this->user->lang['AUTH_PROVIDER_OAUTH_SERVICE_' . strtoupper($actual_name)],
|
||||
'UNIQUE_ID' => (isset($oauth_user_ids[$actual_name])) ? $oauth_user_ids[$actual_name] : null,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return array(
|
||||
'BLOCK_VAR_NAME' => 'oauth',
|
||||
'BLOCK_VARS' => $block_vars,
|
||||
|
||||
'TEMPLATE_FILE' => 'ucp_auth_link_oauth.html',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function unlink_account(array $link_data)
|
||||
{
|
||||
if (!array_key_exists('oauth_service', $link_data) || !$link_data['oauth_service'])
|
||||
{
|
||||
return 'LOGIN_LINK_MISSING_DATA';
|
||||
}
|
||||
|
||||
// Remove user specified in $link_data if possible
|
||||
$user_id = isset($link_data['user_id']) ? $link_data['user_id'] : $this->user->data['user_id'];
|
||||
|
||||
// Remove the link
|
||||
$sql = 'DELETE FROM ' . $this->auth_provider_oauth_token_account_assoc . "
|
||||
WHERE provider = '" . $this->db->sql_escape($link_data['oauth_service']) . "'
|
||||
AND user_id = " . (int) $user_id;
|
||||
$this->db->sql_query($sql);
|
||||
|
||||
// Clear all tokens belonging to the user on this service
|
||||
$service_name = 'auth.provider.oauth.service.' . strtolower($link_data['oauth_service']);
|
||||
$storage = new \phpbb\auth\provider\oauth\token_storage($this->db, $this->user, $this->auth_provider_oauth_token_storage_table, $this->auth_provider_oauth_state_table);
|
||||
$storage->clearToken($service_name);
|
||||
}
|
||||
}
|
||||
51
phpbb/auth/provider/oauth/service/base.php
Normal file
51
phpbb/auth/provider/oauth/service/base.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\auth\provider\oauth\service;
|
||||
|
||||
/**
|
||||
* Base OAuth abstract class that all OAuth services should implement
|
||||
*/
|
||||
abstract class base implements \phpbb\auth\provider\oauth\service\service_interface
|
||||
{
|
||||
/**
|
||||
* External OAuth service provider
|
||||
*
|
||||
* @var \OAuth\Common\Service\ServiceInterface
|
||||
*/
|
||||
protected $service_provider;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get_external_service_provider()
|
||||
{
|
||||
return $this->service_provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get_auth_scope()
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function set_external_service_provider(\OAuth\Common\Service\ServiceInterface $service_provider)
|
||||
{
|
||||
$this->service_provider = $service_provider;
|
||||
}
|
||||
}
|
||||
94
phpbb/auth/provider/oauth/service/bitly.php
Normal file
94
phpbb/auth/provider/oauth/service/bitly.php
Normal file
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\auth\provider\oauth\service;
|
||||
|
||||
/**
|
||||
* Bitly OAuth service
|
||||
*/
|
||||
class bitly extends \phpbb\auth\provider\oauth\service\base
|
||||
{
|
||||
/**
|
||||
* phpBB config
|
||||
*
|
||||
* @var \phpbb\config\config
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* phpBB request
|
||||
*
|
||||
* @var \phpbb\request\request_interface
|
||||
*/
|
||||
protected $request;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \phpbb\config\config $config
|
||||
* @param \phpbb\request\request_interface $request
|
||||
*/
|
||||
public function __construct(\phpbb\config\config $config, \phpbb\request\request_interface $request)
|
||||
{
|
||||
$this->config = $config;
|
||||
$this->request = $request;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get_service_credentials()
|
||||
{
|
||||
return array(
|
||||
'key' => $this->config['auth_oauth_bitly_key'],
|
||||
'secret' => $this->config['auth_oauth_bitly_secret'],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function perform_auth_login()
|
||||
{
|
||||
if (!($this->service_provider instanceof \OAuth\OAuth2\Service\Bitly))
|
||||
{
|
||||
throw new \phpbb\auth\provider\oauth\service\exception('AUTH_PROVIDER_OAUTH_ERROR_INVALID_SERVICE_TYPE');
|
||||
}
|
||||
|
||||
// This was a callback request from bitly, get the token
|
||||
$this->service_provider->requestAccessToken($this->request->variable('code', ''));
|
||||
|
||||
// Send a request with it
|
||||
$result = json_decode($this->service_provider->request('user/info'), true);
|
||||
|
||||
// Return the unique identifier returned from bitly
|
||||
return $result['data']['login'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function perform_token_auth()
|
||||
{
|
||||
if (!($this->service_provider instanceof \OAuth\OAuth2\Service\Bitly))
|
||||
{
|
||||
throw new \phpbb\auth\provider\oauth\service\exception('AUTH_PROVIDER_OAUTH_ERROR_INVALID_SERVICE_TYPE');
|
||||
}
|
||||
|
||||
// Send a request with it
|
||||
$result = json_decode($this->service_provider->request('user/info'), true);
|
||||
|
||||
// Return the unique identifier returned from bitly
|
||||
return $result['data']['login'];
|
||||
}
|
||||
}
|
||||
21
phpbb/auth/provider/oauth/service/exception.php
Normal file
21
phpbb/auth/provider/oauth/service/exception.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\auth\provider\oauth\service;
|
||||
|
||||
/**
|
||||
* OAuth service exception class
|
||||
*/
|
||||
class exception extends \RuntimeException
|
||||
{
|
||||
}
|
||||
94
phpbb/auth/provider/oauth/service/facebook.php
Normal file
94
phpbb/auth/provider/oauth/service/facebook.php
Normal file
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\auth\provider\oauth\service;
|
||||
|
||||
/**
|
||||
* Facebook OAuth service
|
||||
*/
|
||||
class facebook extends base
|
||||
{
|
||||
/**
|
||||
* phpBB config
|
||||
*
|
||||
* @var \phpbb\config\config
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* phpBB request
|
||||
*
|
||||
* @var \phpbb\request\request_interface
|
||||
*/
|
||||
protected $request;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \phpbb\config\config $config
|
||||
* @param \phpbb\request\request_interface $request
|
||||
*/
|
||||
public function __construct(\phpbb\config\config $config, \phpbb\request\request_interface $request)
|
||||
{
|
||||
$this->config = $config;
|
||||
$this->request = $request;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get_service_credentials()
|
||||
{
|
||||
return array(
|
||||
'key' => $this->config['auth_oauth_facebook_key'],
|
||||
'secret' => $this->config['auth_oauth_facebook_secret'],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function perform_auth_login()
|
||||
{
|
||||
if (!($this->service_provider instanceof \OAuth\OAuth2\Service\Facebook))
|
||||
{
|
||||
throw new exception('AUTH_PROVIDER_OAUTH_ERROR_INVALID_SERVICE_TYPE');
|
||||
}
|
||||
|
||||
// This was a callback request, get the token
|
||||
$this->service_provider->requestAccessToken($this->request->variable('code', ''));
|
||||
|
||||
// Send a request with it
|
||||
$result = json_decode($this->service_provider->request('/me'), true);
|
||||
|
||||
// Return the unique identifier
|
||||
return $result['id'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function perform_token_auth()
|
||||
{
|
||||
if (!($this->service_provider instanceof \OAuth\OAuth2\Service\Facebook))
|
||||
{
|
||||
throw new exception('AUTH_PROVIDER_OAUTH_ERROR_INVALID_SERVICE_TYPE');
|
||||
}
|
||||
|
||||
// Send a request with it
|
||||
$result = json_decode($this->service_provider->request('/me'), true);
|
||||
|
||||
// Return the unique identifier
|
||||
return $result['id'];
|
||||
}
|
||||
}
|
||||
105
phpbb/auth/provider/oauth/service/google.php
Normal file
105
phpbb/auth/provider/oauth/service/google.php
Normal file
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\auth\provider\oauth\service;
|
||||
|
||||
/**
|
||||
* Google OAuth service
|
||||
*/
|
||||
class google extends base
|
||||
{
|
||||
/**
|
||||
* phpBB config
|
||||
*
|
||||
* @var \phpbb\config\config
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* phpBB request
|
||||
*
|
||||
* @var \phpbb\request\request_interface
|
||||
*/
|
||||
protected $request;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \phpbb\config\config $config
|
||||
* @param \phpbb\request\request_interface $request
|
||||
*/
|
||||
public function __construct(\phpbb\config\config $config, \phpbb\request\request_interface $request)
|
||||
{
|
||||
$this->config = $config;
|
||||
$this->request = $request;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get_auth_scope()
|
||||
{
|
||||
return array(
|
||||
'userinfo_email',
|
||||
'userinfo_profile',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get_service_credentials()
|
||||
{
|
||||
return array(
|
||||
'key' => $this->config['auth_oauth_google_key'],
|
||||
'secret' => $this->config['auth_oauth_google_secret'],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function perform_auth_login()
|
||||
{
|
||||
if (!($this->service_provider instanceof \OAuth\OAuth2\Service\Google))
|
||||
{
|
||||
throw new exception('AUTH_PROVIDER_OAUTH_ERROR_INVALID_SERVICE_TYPE');
|
||||
}
|
||||
|
||||
// This was a callback request, get the token
|
||||
$this->service_provider->requestAccessToken($this->request->variable('code', ''));
|
||||
|
||||
// Send a request with it
|
||||
$result = json_decode($this->service_provider->request('https://www.googleapis.com/oauth2/v1/userinfo'), true);
|
||||
|
||||
// Return the unique identifier
|
||||
return $result['id'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function perform_token_auth()
|
||||
{
|
||||
if (!($this->service_provider instanceof \OAuth\OAuth2\Service\Google))
|
||||
{
|
||||
throw new exception('AUTH_PROVIDER_OAUTH_ERROR_INVALID_SERVICE_TYPE');
|
||||
}
|
||||
|
||||
// Send a request with it
|
||||
$result = json_decode($this->service_provider->request('https://www.googleapis.com/oauth2/v1/userinfo'), true);
|
||||
|
||||
// Return the unique identifier
|
||||
return $result['id'];
|
||||
}
|
||||
}
|
||||
73
phpbb/auth/provider/oauth/service/service_interface.php
Normal file
73
phpbb/auth/provider/oauth/service/service_interface.php
Normal file
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\auth\provider\oauth\service;
|
||||
|
||||
/**
|
||||
* OAuth service interface
|
||||
*/
|
||||
interface service_interface
|
||||
{
|
||||
/**
|
||||
* Returns an array of the scopes necessary for auth
|
||||
*
|
||||
* @return array An array of the required scopes
|
||||
*/
|
||||
public function get_auth_scope();
|
||||
|
||||
/**
|
||||
* Returns the external library service provider once it has been set
|
||||
*
|
||||
* @param \OAuth\Common\Service\ServiceInterface|null
|
||||
*/
|
||||
public function get_external_service_provider();
|
||||
|
||||
/**
|
||||
* Returns an array containing the service credentials belonging to requested
|
||||
* service.
|
||||
*
|
||||
* @return array An array containing the 'key' and the 'secret' of the
|
||||
* service in the form:
|
||||
* array(
|
||||
* 'key' => string
|
||||
* 'secret' => string
|
||||
* )
|
||||
*/
|
||||
public function get_service_credentials();
|
||||
|
||||
/**
|
||||
* Returns the results of the authentication in json format
|
||||
*
|
||||
* @throws \phpbb\auth\provider\oauth\service\exception
|
||||
* @return string The unique identifier returned by the service provider
|
||||
* that is used to authenticate the user with phpBB.
|
||||
*/
|
||||
public function perform_auth_login();
|
||||
|
||||
/**
|
||||
* Returns the results of the authentication in json format
|
||||
* Use this function when the user already has an access token
|
||||
*
|
||||
* @throws \phpbb\auth\provider\oauth\service\exception
|
||||
* @return string The unique identifier returned by the service provider
|
||||
* that is used to authenticate the user with phpBB.
|
||||
*/
|
||||
public function perform_token_auth();
|
||||
|
||||
/**
|
||||
* Sets the external library service provider
|
||||
*
|
||||
* @param \OAuth\Common\Service\ServiceInterface $service_provider
|
||||
*/
|
||||
public function set_external_service_provider(\OAuth\Common\Service\ServiceInterface $service_provider);
|
||||
}
|
||||
102
phpbb/auth/provider/oauth/service/twitter.php
Normal file
102
phpbb/auth/provider/oauth/service/twitter.php
Normal file
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\auth\provider\oauth\service;
|
||||
|
||||
/**
|
||||
* Twitter OAuth service
|
||||
*/
|
||||
class twitter extends \phpbb\auth\provider\oauth\service\base
|
||||
{
|
||||
/**
|
||||
* phpBB config
|
||||
*
|
||||
* @var \phpbb\config\config
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* phpBB request
|
||||
*
|
||||
* @var \phpbb\request\request_interface
|
||||
*/
|
||||
protected $request;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \phpbb\config\config $config
|
||||
* @param \phpbb\request\request_interface $request
|
||||
*/
|
||||
public function __construct(\phpbb\config\config $config, \phpbb\request\request_interface $request)
|
||||
{
|
||||
$this->config = $config;
|
||||
$this->request = $request;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get_service_credentials()
|
||||
{
|
||||
return array(
|
||||
'key' => $this->config['auth_oauth_twitter_key'],
|
||||
'secret' => $this->config['auth_oauth_twitter_secret'],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function perform_auth_login()
|
||||
{
|
||||
if (!($this->service_provider instanceof \OAuth\OAuth1\Service\Twitter))
|
||||
{
|
||||
throw new \phpbb\auth\provider\oauth\service\exception('AUTH_PROVIDER_OAUTH_ERROR_INVALID_SERVICE_TYPE');
|
||||
}
|
||||
|
||||
$storage = $this->service_provider->getStorage();
|
||||
$token = $storage->retrieveAccessToken('Twitter');
|
||||
$tokensecret = $token->getRequestTokenSecret();
|
||||
|
||||
// This was a callback request from twitter, get the token
|
||||
$this->service_provider->requestAccessToken(
|
||||
$this->request->variable('oauth_token', ''),
|
||||
$this->request->variable('oauth_verifier', ''),
|
||||
$tokensecret
|
||||
);
|
||||
|
||||
// Send a request with it
|
||||
$result = json_decode($this->service_provider->request('account/verify_credentials.json'), true);
|
||||
|
||||
// Return the unique identifier returned from twitter
|
||||
return $result['id'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function perform_token_auth()
|
||||
{
|
||||
if (!($this->service_provider instanceof \OAuth\OAuth1\Service\Twitter))
|
||||
{
|
||||
throw new \phpbb\auth\provider\oauth\service\exception('AUTH_PROVIDER_OAUTH_ERROR_INVALID_SERVICE_TYPE');
|
||||
}
|
||||
|
||||
// Send a request with it
|
||||
$result = json_decode($this->service_provider->request('account/verify_credentials.json'), true);
|
||||
|
||||
// Return the unique identifier returned from twitter
|
||||
return $result['id'];
|
||||
}
|
||||
}
|
||||
592
phpbb/auth/provider/oauth/token_storage.php
Normal file
592
phpbb/auth/provider/oauth/token_storage.php
Normal file
@@ -0,0 +1,592 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\auth\provider\oauth;
|
||||
|
||||
use OAuth\OAuth1\Token\StdOAuth1Token;
|
||||
use OAuth\Common\Token\TokenInterface;
|
||||
use OAuth\Common\Storage\TokenStorageInterface;
|
||||
use OAuth\Common\Storage\Exception\TokenNotFoundException;
|
||||
use OAuth\Common\Storage\Exception\AuthorizationStateNotFoundException;
|
||||
|
||||
/**
|
||||
* OAuth storage wrapper for phpbb's cache
|
||||
*/
|
||||
class token_storage implements TokenStorageInterface
|
||||
{
|
||||
/**
|
||||
* Cache driver.
|
||||
*
|
||||
* @var \phpbb\db\driver\driver_interface
|
||||
*/
|
||||
protected $db;
|
||||
|
||||
/**
|
||||
* phpBB user
|
||||
*
|
||||
* @var \phpbb\user
|
||||
*/
|
||||
protected $user;
|
||||
|
||||
/**
|
||||
* OAuth token table
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $oauth_token_table;
|
||||
|
||||
/**
|
||||
* OAuth state table
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $oauth_state_table;
|
||||
|
||||
/**
|
||||
* @var object|TokenInterface
|
||||
*/
|
||||
protected $cachedToken;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $cachedState;
|
||||
|
||||
/**
|
||||
* Creates token storage for phpBB.
|
||||
*
|
||||
* @param \phpbb\db\driver\driver_interface $db
|
||||
* @param \phpbb\user $user
|
||||
* @param string $oauth_token_table
|
||||
* @param string $oauth_state_table
|
||||
*/
|
||||
public function __construct(\phpbb\db\driver\driver_interface $db, \phpbb\user $user, $oauth_token_table, $oauth_state_table)
|
||||
{
|
||||
$this->db = $db;
|
||||
$this->user = $user;
|
||||
$this->oauth_token_table = $oauth_token_table;
|
||||
$this->oauth_state_table = $oauth_state_table;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function retrieveAccessToken($service)
|
||||
{
|
||||
$service = $this->get_service_name_for_db($service);
|
||||
|
||||
if ($this->cachedToken instanceof TokenInterface)
|
||||
{
|
||||
return $this->cachedToken;
|
||||
}
|
||||
|
||||
$data = array(
|
||||
'user_id' => (int) $this->user->data['user_id'],
|
||||
'provider' => $service,
|
||||
);
|
||||
|
||||
if ((int) $this->user->data['user_id'] === ANONYMOUS)
|
||||
{
|
||||
$data['session_id'] = $this->user->data['session_id'];
|
||||
}
|
||||
|
||||
return $this->_retrieve_access_token($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function storeAccessToken($service, TokenInterface $token)
|
||||
{
|
||||
$service = $this->get_service_name_for_db($service);
|
||||
|
||||
$this->cachedToken = $token;
|
||||
|
||||
$data = array(
|
||||
'oauth_token' => $this->json_encode_token($token),
|
||||
);
|
||||
|
||||
$sql = 'UPDATE ' . $this->oauth_token_table . '
|
||||
SET ' . $this->db->sql_build_array('UPDATE', $data) . '
|
||||
WHERE user_id = ' . (int) $this->user->data['user_id'] . '
|
||||
' . ((int) $this->user->data['user_id'] === ANONYMOUS ? "AND session_id = '" . $this->db->sql_escape($this->user->data['session_id']) . "'" : '') . "
|
||||
AND provider = '" . $this->db->sql_escape($service) . "'";
|
||||
$this->db->sql_query($sql);
|
||||
|
||||
if (!$this->db->sql_affectedrows())
|
||||
{
|
||||
$data = array(
|
||||
'user_id' => (int) $this->user->data['user_id'],
|
||||
'provider' => $service,
|
||||
'oauth_token' => $this->json_encode_token($token),
|
||||
'session_id' => $this->user->data['session_id'],
|
||||
);
|
||||
|
||||
$sql = 'INSERT INTO ' . $this->oauth_token_table . $this->db->sql_build_array('INSERT', $data);
|
||||
|
||||
$this->db->sql_query($sql);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function hasAccessToken($service)
|
||||
{
|
||||
$service = $this->get_service_name_for_db($service);
|
||||
|
||||
if ($this->cachedToken)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
$data = array(
|
||||
'user_id' => (int) $this->user->data['user_id'],
|
||||
'provider' => $service,
|
||||
);
|
||||
|
||||
if ((int) $this->user->data['user_id'] === ANONYMOUS)
|
||||
{
|
||||
$data['session_id'] = $this->user->data['session_id'];
|
||||
}
|
||||
|
||||
return $this->_has_acess_token($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function clearToken($service)
|
||||
{
|
||||
$service = $this->get_service_name_for_db($service);
|
||||
|
||||
$this->cachedToken = null;
|
||||
|
||||
$sql = 'DELETE FROM ' . $this->oauth_token_table . '
|
||||
WHERE user_id = ' . (int) $this->user->data['user_id'] . "
|
||||
AND provider = '" . $this->db->sql_escape($service) . "'";
|
||||
|
||||
if ((int) $this->user->data['user_id'] === ANONYMOUS)
|
||||
{
|
||||
$sql .= " AND session_id = '" . $this->db->sql_escape($this->user->data['session_id']) . "'";
|
||||
}
|
||||
|
||||
$this->db->sql_query($sql);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function clearAllTokens()
|
||||
{
|
||||
$this->cachedToken = null;
|
||||
|
||||
$sql = 'DELETE FROM ' . $this->oauth_token_table . '
|
||||
WHERE user_id = ' . (int) $this->user->data['user_id'];
|
||||
|
||||
if ((int) $this->user->data['user_id'] === ANONYMOUS)
|
||||
{
|
||||
$sql .= " AND session_id = '" . $this->db->sql_escape($this->user->data['session_id']) . "'";
|
||||
}
|
||||
|
||||
$this->db->sql_query($sql);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function storeAuthorizationState($service, $state)
|
||||
{
|
||||
$service = $this->get_service_name_for_db($service);
|
||||
|
||||
$this->cachedState = $state;
|
||||
|
||||
$data = array(
|
||||
'user_id' => (int) $this->user->data['user_id'],
|
||||
'provider' => $service,
|
||||
'oauth_state' => $state,
|
||||
'session_id' => $this->user->data['session_id'],
|
||||
);
|
||||
|
||||
$sql = 'INSERT INTO ' . $this->oauth_state_table . '
|
||||
' . $this->db->sql_build_array('INSERT', $data);
|
||||
$this->db->sql_query($sql);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function hasAuthorizationState($service)
|
||||
{
|
||||
$service = $this->get_service_name_for_db($service);
|
||||
|
||||
if ($this->cachedState)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
$data = array(
|
||||
'user_id' => (int) $this->user->data['user_id'],
|
||||
'provider' => $service,
|
||||
);
|
||||
|
||||
if ((int) $this->user->data['user_id'] === ANONYMOUS)
|
||||
{
|
||||
$data['session_id'] = $this->user->data['session_id'];
|
||||
}
|
||||
|
||||
return (bool) $this->get_state_row($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function retrieveAuthorizationState($service)
|
||||
{
|
||||
$service = $this->get_service_name_for_db($service);
|
||||
|
||||
if ($this->cachedState)
|
||||
{
|
||||
return $this->cachedState;
|
||||
}
|
||||
|
||||
$data = array(
|
||||
'user_id' => (int) $this->user->data['user_id'],
|
||||
'provider' => $service,
|
||||
);
|
||||
|
||||
if ((int) $this->user->data['user_id'] === ANONYMOUS)
|
||||
{
|
||||
$data['session_id'] = $this->user->data['session_id'];
|
||||
}
|
||||
|
||||
return $this->get_state_row($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function clearAuthorizationState($service)
|
||||
{
|
||||
$service = $this->get_service_name_for_db($service);
|
||||
|
||||
$this->cachedState = null;
|
||||
|
||||
$sql = 'DELETE FROM ' . $this->oauth_state_table . '
|
||||
WHERE user_id = ' . (int) $this->user->data['user_id'] . "
|
||||
AND provider = '" . $this->db->sql_escape($service) . "'";
|
||||
|
||||
if ((int) $this->user->data['user_id'] === ANONYMOUS)
|
||||
{
|
||||
$sql .= " AND session_id = '" . $this->db->sql_escape($this->user->data['session_id']) . "'";
|
||||
}
|
||||
|
||||
$this->db->sql_query($sql);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function clearAllAuthorizationStates()
|
||||
{
|
||||
$this->cachedState = null;
|
||||
|
||||
$sql = 'DELETE FROM ' . $this->oauth_state_table . '
|
||||
WHERE user_id = ' . (int) $this->user->data['user_id'];
|
||||
|
||||
if ((int) $this->user->data['user_id'] === ANONYMOUS)
|
||||
{
|
||||
$sql .= " AND session_id = '" . $this->db->sql_escape($this->user->data['session_id']) . "'";
|
||||
}
|
||||
|
||||
$this->db->sql_query($sql);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the user_id field in the database assosciated with the token
|
||||
*
|
||||
* @param int $user_id
|
||||
*/
|
||||
public function set_user_id($user_id)
|
||||
{
|
||||
if (!$this->cachedToken)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$sql = 'UPDATE ' . $this->oauth_token_table . '
|
||||
SET ' . $this->db->sql_build_array('UPDATE', array(
|
||||
'user_id' => (int) $user_id
|
||||
)) . '
|
||||
WHERE user_id = ' . (int) $this->user->data['user_id'] . "
|
||||
AND session_id = '" . $this->db->sql_escape($this->user->data['session_id']) . "'";
|
||||
$this->db->sql_query($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if an access token exists solely by the session_id of the user
|
||||
*
|
||||
* @param string $service The name of the OAuth service
|
||||
* @return bool true if they have token, false if they don't
|
||||
*/
|
||||
public function has_access_token_by_session($service)
|
||||
{
|
||||
$service = $this->get_service_name_for_db($service);
|
||||
|
||||
if ($this->cachedToken)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
$data = array(
|
||||
'session_id' => $this->user->data['session_id'],
|
||||
'provider' => $service,
|
||||
);
|
||||
|
||||
return $this->_has_acess_token($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if a state exists solely by the session_id of the user
|
||||
*
|
||||
* @param string $service The name of the OAuth service
|
||||
* @return bool true if they have state, false if they don't
|
||||
*/
|
||||
public function has_state_by_session($service)
|
||||
{
|
||||
$service = $this->get_service_name_for_db($service);
|
||||
|
||||
if ($this->cachedState)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
$data = array(
|
||||
'session_id' => $this->user->data['session_id'],
|
||||
'provider' => $service,
|
||||
);
|
||||
|
||||
return (bool) $this->get_state_row($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper function that performs the query for has access token functions
|
||||
*
|
||||
* @param array $data
|
||||
* @return bool
|
||||
*/
|
||||
protected function _has_acess_token($data)
|
||||
{
|
||||
return (bool) $this->get_access_token_row($data);
|
||||
}
|
||||
|
||||
public function retrieve_access_token_by_session($service)
|
||||
{
|
||||
$service = $this->get_service_name_for_db($service);
|
||||
|
||||
if ($this->cachedToken instanceof TokenInterface)
|
||||
{
|
||||
return $this->cachedToken;
|
||||
}
|
||||
|
||||
$data = array(
|
||||
'session_id' => $this->user->data['session_id'],
|
||||
'provider' => $service,
|
||||
);
|
||||
|
||||
return $this->_retrieve_access_token($data);
|
||||
}
|
||||
|
||||
public function retrieve_state_by_session($service)
|
||||
{
|
||||
$service = $this->get_service_name_for_db($service);
|
||||
|
||||
if ($this->cachedState)
|
||||
{
|
||||
return $this->cachedState;
|
||||
}
|
||||
|
||||
$data = array(
|
||||
'session_id' => $this->user->data['session_id'],
|
||||
'provider' => $service,
|
||||
);
|
||||
|
||||
return $this->_retrieve_state($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper function that performs the query for retrieve access token functions
|
||||
* Also checks if the token is a valid token
|
||||
*
|
||||
* @param array $data
|
||||
* @return mixed
|
||||
* @throws \OAuth\Common\Storage\Exception\TokenNotFoundException
|
||||
*/
|
||||
protected function _retrieve_access_token($data)
|
||||
{
|
||||
$row = $this->get_access_token_row($data);
|
||||
|
||||
if (!$row)
|
||||
{
|
||||
throw new TokenNotFoundException('AUTH_PROVIDER_OAUTH_TOKEN_ERROR_NOT_STORED');
|
||||
}
|
||||
|
||||
$token = $this->json_decode_token($row['oauth_token']);
|
||||
|
||||
// Ensure that the token was serialized/unserialized correctly
|
||||
if (!($token instanceof TokenInterface))
|
||||
{
|
||||
$this->clearToken($data['provider']);
|
||||
throw new TokenNotFoundException('AUTH_PROVIDER_OAUTH_TOKEN_ERROR_INCORRECTLY_STORED');
|
||||
}
|
||||
|
||||
$this->cachedToken = $token;
|
||||
return $token;
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper function that performs the query for retrieve state functions
|
||||
*
|
||||
* @param array $data
|
||||
* @return mixed
|
||||
* @throws \OAuth\Common\Storage\Exception\AuthorizationStateNotFoundException
|
||||
*/
|
||||
protected function _retrieve_state($data)
|
||||
{
|
||||
$row = $this->get_state_row($data);
|
||||
|
||||
if (!$row)
|
||||
{
|
||||
throw new AuthorizationStateNotFoundException();
|
||||
}
|
||||
|
||||
$this->cachedState = $row['oauth_state'];
|
||||
return $this->cachedState;
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper function that performs the query for retrieving an access token
|
||||
*
|
||||
* @param array $data
|
||||
* @return mixed
|
||||
*/
|
||||
protected function get_access_token_row($data)
|
||||
{
|
||||
$sql = 'SELECT oauth_token FROM ' . $this->oauth_token_table . '
|
||||
WHERE ' . $this->db->sql_build_array('SELECT', $data);
|
||||
$result = $this->db->sql_query($sql);
|
||||
$row = $this->db->sql_fetchrow($result);
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
return $row;
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper function that performs the query for retrieving a state
|
||||
*
|
||||
* @param array $data
|
||||
* @return mixed
|
||||
*/
|
||||
protected function get_state_row($data)
|
||||
{
|
||||
$sql = 'SELECT oauth_state FROM ' . $this->oauth_state_table . '
|
||||
WHERE ' . $this->db->sql_build_array('SELECT', $data);
|
||||
$result = $this->db->sql_query($sql);
|
||||
$row = $this->db->sql_fetchrow($result);
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
return $row;
|
||||
}
|
||||
|
||||
public function json_encode_token(TokenInterface $token)
|
||||
{
|
||||
$members = array(
|
||||
'accessToken' => $token->getAccessToken(),
|
||||
'endOfLife' => $token->getEndOfLife(),
|
||||
'extraParams' => $token->getExtraParams(),
|
||||
'refreshToken' => $token->getRefreshToken(),
|
||||
|
||||
'token_class' => get_class($token),
|
||||
);
|
||||
|
||||
// Handle additional data needed for OAuth1 tokens
|
||||
if ($token instanceof StdOAuth1Token)
|
||||
{
|
||||
$members['requestToken'] = $token->getRequestToken();
|
||||
$members['requestTokenSecret'] = $token->getRequestTokenSecret();
|
||||
$members['accessTokenSecret'] = $token->getAccessTokenSecret();
|
||||
}
|
||||
|
||||
return json_encode($members);
|
||||
}
|
||||
|
||||
public function json_decode_token($json)
|
||||
{
|
||||
$token_data = json_decode($json, true);
|
||||
|
||||
if ($token_data === null)
|
||||
{
|
||||
throw new TokenNotFoundException('AUTH_PROVIDER_OAUTH_TOKEN_ERROR_INCORRECTLY_STORED');
|
||||
}
|
||||
|
||||
$token_class = $token_data['token_class'];
|
||||
$access_token = $token_data['accessToken'];
|
||||
$refresh_token = $token_data['refreshToken'];
|
||||
$endOfLife = $token_data['endOfLife'];
|
||||
$extra_params = $token_data['extraParams'];
|
||||
|
||||
// Create the token
|
||||
$token = new $token_class($access_token, $refresh_token, TokenInterface::EOL_NEVER_EXPIRES, $extra_params);
|
||||
$token->setEndOfLife($endOfLife);
|
||||
|
||||
// Handle OAuth 1.0 specific elements
|
||||
if ($token instanceof StdOAuth1Token)
|
||||
{
|
||||
$token->setRequestToken($token_data['requestToken']);
|
||||
$token->setRequestTokenSecret($token_data['requestTokenSecret']);
|
||||
$token->setAccessTokenSecret($token_data['accessTokenSecret']);
|
||||
}
|
||||
|
||||
return $token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the service as it must be stored in the database.
|
||||
*
|
||||
* @param string $service The name of the OAuth service
|
||||
* @return string The name of the OAuth service as it needs to be stored
|
||||
* in the database.
|
||||
*/
|
||||
protected function get_service_name_for_db($service)
|
||||
{
|
||||
// Enforce the naming convention for oauth services
|
||||
if (strpos($service, 'auth.provider.oauth.service.') !== 0)
|
||||
{
|
||||
$service = 'auth.provider.oauth.service.' . strtolower($service);
|
||||
}
|
||||
|
||||
return $service;
|
||||
}
|
||||
}
|
||||
197
phpbb/auth/provider/provider_interface.php
Normal file
197
phpbb/auth/provider/provider_interface.php
Normal file
@@ -0,0 +1,197 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\auth\provider;
|
||||
|
||||
/**
|
||||
* The interface authentication provider classes have to implement.
|
||||
*/
|
||||
interface provider_interface
|
||||
{
|
||||
/**
|
||||
* Checks whether the user is currently identified to the authentication
|
||||
* provider.
|
||||
* Called in acp_board while setting authentication plugins.
|
||||
* Changing to an authentication provider will not be permitted in acp_board
|
||||
* if there is an error.
|
||||
*
|
||||
* @return boolean|string False if the user is identified, otherwise an
|
||||
* error message, or null if not implemented.
|
||||
*/
|
||||
public function init();
|
||||
|
||||
/**
|
||||
* Performs login.
|
||||
*
|
||||
* @param string $username The name of the user being authenticated.
|
||||
* @param string $password The password of the user.
|
||||
* @return array An associative array of the format:
|
||||
* array(
|
||||
* 'status' => status constant
|
||||
* 'error_msg' => string
|
||||
* 'user_row' => array
|
||||
* )
|
||||
* A fourth key of the array may be present:
|
||||
* 'redirect_data' This key is only used when 'status' is
|
||||
* equal to LOGIN_SUCCESS_LINK_PROFILE and its value is an
|
||||
* associative array that is turned into GET variables on
|
||||
* the redirect url.
|
||||
*/
|
||||
public function login($username, $password);
|
||||
|
||||
/**
|
||||
* Autologin function
|
||||
*
|
||||
* @return array|null containing the user row, empty if no auto login
|
||||
* should take place, or null if not impletmented.
|
||||
*/
|
||||
public function autologin();
|
||||
|
||||
/**
|
||||
* This function is used to output any required fields in the authentication
|
||||
* admin panel. It also defines any required configuration table fields.
|
||||
*
|
||||
* @return array|null Returns null if not implemented or an array of the
|
||||
* configuration fields of the provider.
|
||||
*/
|
||||
public function acp();
|
||||
|
||||
/**
|
||||
* This function updates the template with variables related to the acp
|
||||
* options with whatever configuraton values are passed to it as an array.
|
||||
* It then returns the name of the acp file related to this authentication
|
||||
* provider.
|
||||
* @param array $new_config Contains the new configuration values that
|
||||
* have been set in acp_board.
|
||||
* @return array|null Returns null if not implemented or an array with
|
||||
* the template file name and an array of the vars
|
||||
* that the template needs that must conform to the
|
||||
* following example:
|
||||
* array(
|
||||
* 'TEMPLATE_FILE' => string,
|
||||
* 'TEMPLATE_VARS' => array(...),
|
||||
* )
|
||||
* An optional third element may be added to this
|
||||
* array: 'BLOCK_VAR_NAME'. If this is present,
|
||||
* then its value should be a string that is used
|
||||
* to designate the name of the loop used in the
|
||||
* ACP template file. When this is present, an
|
||||
* additional key named 'BLOCK_VARS' is required.
|
||||
* This must be an array containing at least one
|
||||
* array of variables that will be assigned during
|
||||
* the loop in the template. An example of this is
|
||||
* presented below:
|
||||
* array(
|
||||
* 'BLOCK_VAR_NAME' => string,
|
||||
* 'BLOCK_VARS' => array(
|
||||
* 'KEY IS UNIMPORTANT' => array(...),
|
||||
* ),
|
||||
* 'TEMPLATE_FILE' => string,
|
||||
* 'TEMPLATE_VARS' => array(...),
|
||||
* )
|
||||
*/
|
||||
public function get_acp_template($new_config);
|
||||
|
||||
/**
|
||||
* Returns an array of data necessary to build custom elements on the login
|
||||
* form.
|
||||
*
|
||||
* @return array|null If this function is not implemented on an auth
|
||||
* provider then it returns null. If it is implemented
|
||||
* it will return an array of up to four elements of
|
||||
* which only 'TEMPLATE_FILE'. If 'BLOCK_VAR_NAME' is
|
||||
* present then 'BLOCK_VARS' must also be present in
|
||||
* the array. The fourth element 'VARS' is also
|
||||
* optional. The array, with all four elements present
|
||||
* looks like the following:
|
||||
* array(
|
||||
* 'TEMPLATE_FILE' => string,
|
||||
* 'BLOCK_VAR_NAME' => string,
|
||||
* 'BLOCK_VARS' => array(...),
|
||||
* 'VARS' => array(...),
|
||||
* )
|
||||
*/
|
||||
public function get_login_data();
|
||||
|
||||
/**
|
||||
* Performs additional actions during logout.
|
||||
*
|
||||
* @param array $data An array corresponding to
|
||||
* \phpbb\session::data
|
||||
* @param boolean $new_session True for a new session, false for no new
|
||||
* session.
|
||||
*/
|
||||
public function logout($data, $new_session);
|
||||
|
||||
/**
|
||||
* The session validation function checks whether the user is still logged
|
||||
* into phpBB.
|
||||
*
|
||||
* @param array $user
|
||||
* @return boolean true if the given user is authenticated, false if the
|
||||
* session should be closed, or null if not implemented.
|
||||
*/
|
||||
public function validate_session($user);
|
||||
|
||||
/**
|
||||
* Checks to see if $login_link_data contains all information except for the
|
||||
* user_id of an account needed to successfully link an external account to
|
||||
* a forum account.
|
||||
*
|
||||
* @param array $login_link_data Any data needed to link a phpBB account to
|
||||
* an external account.
|
||||
* @return string|null Returns a string with a language constant if there
|
||||
* is data missing or null if there is no error.
|
||||
*/
|
||||
public function login_link_has_necessary_data($login_link_data);
|
||||
|
||||
/**
|
||||
* Links an external account to a phpBB account.
|
||||
*
|
||||
* @param array $link_data Any data needed to link a phpBB account to
|
||||
* an external account.
|
||||
*/
|
||||
public function link_account(array $link_data);
|
||||
|
||||
/**
|
||||
* Returns an array of data necessary to build the ucp_auth_link page
|
||||
*
|
||||
* @param int $user_id User ID for whom the data should be retrieved.
|
||||
* defaults to 0, which is not a valid ID. The method
|
||||
* should fall back to the current user's ID in this
|
||||
* case.
|
||||
* @return array|null If this function is not implemented on an auth
|
||||
* provider then it returns null. If it is implemented
|
||||
* it will return an array of up to four elements of
|
||||
* which only 'TEMPLATE_FILE'. If 'BLOCK_VAR_NAME' is
|
||||
* present then 'BLOCK_VARS' must also be present in
|
||||
* the array. The fourth element 'VARS' is also
|
||||
* optional. The array, with all four elements present
|
||||
* looks like the following:
|
||||
* array(
|
||||
* 'TEMPLATE_FILE' => string,
|
||||
* 'BLOCK_VAR_NAME' => string,
|
||||
* 'BLOCK_VARS' => array(...),
|
||||
* 'VARS' => array(...),
|
||||
* )
|
||||
*/
|
||||
public function get_auth_link_data($user_id = 0);
|
||||
|
||||
/**
|
||||
* Unlinks an external account from a phpBB account.
|
||||
*
|
||||
* @param array $link_data Any data needed to unlink a phpBB account
|
||||
* from a phpbb account.
|
||||
*/
|
||||
public function unlink_account(array $link_data);
|
||||
}
|
||||
67
phpbb/auth/provider_collection.php
Normal file
67
phpbb/auth/provider_collection.php
Normal file
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\auth;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Collection of auth providers to be configured at container compile time.
|
||||
*/
|
||||
class provider_collection extends \phpbb\di\service_collection
|
||||
{
|
||||
/** @var \phpbb\config\config phpBB Config */
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param ContainerInterface $container Container object
|
||||
* @param \phpbb\config\config $config phpBB config
|
||||
*/
|
||||
public function __construct(ContainerInterface $container, \phpbb\config\config $config)
|
||||
{
|
||||
$this->container = $container;
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an auth provider.
|
||||
*
|
||||
* @param string $provider_name The name of the auth provider
|
||||
* @return object Default auth provider selected in config if it
|
||||
* does exist. Otherwise the standard db auth
|
||||
* provider.
|
||||
* @throws \RuntimeException If neither the auth provider that
|
||||
* is specified by the phpBB config nor the db
|
||||
* auth provider exist. The db auth provider
|
||||
* should always exist in a phpBB installation.
|
||||
*/
|
||||
public function get_provider($provider_name = '')
|
||||
{
|
||||
$provider_name = ($provider_name !== '') ? $provider_name : basename(trim($this->config['auth_method']));
|
||||
if ($this->offsetExists('auth.provider.' . $provider_name))
|
||||
{
|
||||
return $this->offsetGet('auth.provider.' . $provider_name);
|
||||
}
|
||||
// Revert to db auth provider if selected method does not exist
|
||||
else if ($this->offsetExists('auth.provider.db'))
|
||||
{
|
||||
return $this->offsetGet('auth.provider.db');
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new \RuntimeException(sprintf('The authentication provider for the authentication method "%1$s" does not exist. It was not possible to recover from this by reverting to the database authentication provider.', $this->config['auth_method']));
|
||||
}
|
||||
}
|
||||
}
|
||||
152
phpbb/avatar/driver/driver.php
Normal file
152
phpbb/avatar/driver/driver.php
Normal file
@@ -0,0 +1,152 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\avatar\driver;
|
||||
|
||||
/**
|
||||
* Base class for avatar drivers
|
||||
*/
|
||||
abstract class driver implements \phpbb\avatar\driver\driver_interface
|
||||
{
|
||||
/**
|
||||
* Avatar driver name
|
||||
* @var string
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
* Current board configuration
|
||||
* @var \phpbb\config\config
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/** @var \FastImageSize\FastImageSize */
|
||||
protected $imagesize;
|
||||
|
||||
/**
|
||||
* Current $phpbb_root_path
|
||||
* @var string
|
||||
*/
|
||||
protected $phpbb_root_path;
|
||||
|
||||
/**
|
||||
* Current $php_ext
|
||||
* @var string
|
||||
*/
|
||||
protected $php_ext;
|
||||
|
||||
/**
|
||||
* Path Helper
|
||||
* @var \phpbb\path_helper
|
||||
*/
|
||||
protected $path_helper;
|
||||
|
||||
/**
|
||||
* Cache driver
|
||||
* @var \phpbb\cache\driver\driver_interface
|
||||
*/
|
||||
protected $cache;
|
||||
|
||||
/**
|
||||
* Array of allowed avatar image extensions
|
||||
* Array is used for setting the allowed extensions in the fileupload class
|
||||
* and as a base for a regex of allowed extensions, which will be formed by
|
||||
* imploding the array with a "|".
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $allowed_extensions = array(
|
||||
'gif',
|
||||
'jpg',
|
||||
'jpeg',
|
||||
'png',
|
||||
);
|
||||
|
||||
/**
|
||||
* Construct a driver object
|
||||
*
|
||||
* @param \phpbb\config\config $config phpBB configuration
|
||||
* @param \FastImageSize\FastImageSize $imagesize FastImageSize class
|
||||
* @param string $phpbb_root_path Path to the phpBB root
|
||||
* @param string $php_ext PHP file extension
|
||||
* @param \phpbb\path_helper $path_helper phpBB path helper
|
||||
* @param \phpbb\cache\driver\driver_interface $cache Cache driver
|
||||
*/
|
||||
public function __construct(\phpbb\config\config $config, \FastImageSize\FastImageSize $imagesize, $phpbb_root_path, $php_ext, \phpbb\path_helper $path_helper, \phpbb\cache\driver\driver_interface $cache = null)
|
||||
{
|
||||
$this->config = $config;
|
||||
$this->imagesize = $imagesize;
|
||||
$this->phpbb_root_path = $phpbb_root_path;
|
||||
$this->php_ext = $php_ext;
|
||||
$this->path_helper = $path_helper;
|
||||
$this->cache = $cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get_custom_html($user, $row, $alt = '')
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function prepare_form_acp($user)
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function delete($row)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get_name()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get_config_name()
|
||||
{
|
||||
return preg_replace('#^phpbb\\\\avatar\\\\driver\\\\#', '', get_class($this));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get_acp_template_name()
|
||||
{
|
||||
return 'acp_avatar_options_' . $this->get_config_name() . '.html';
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the driver.
|
||||
*
|
||||
* @param string $name Driver name
|
||||
*/
|
||||
public function set_name($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
}
|
||||
}
|
||||
127
phpbb/avatar/driver/driver_interface.php
Normal file
127
phpbb/avatar/driver/driver_interface.php
Normal file
@@ -0,0 +1,127 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\avatar\driver;
|
||||
|
||||
/**
|
||||
* Interface for avatar drivers
|
||||
*/
|
||||
interface driver_interface
|
||||
{
|
||||
/**
|
||||
* Returns the name of the driver.
|
||||
*
|
||||
* @return string Name of driver.
|
||||
*/
|
||||
public function get_name();
|
||||
|
||||
/**
|
||||
* Returns the config name of the driver. To be used in accessing the CONFIG variables.
|
||||
*
|
||||
* @return string Config name of driver.
|
||||
*/
|
||||
public function get_config_name();
|
||||
|
||||
/**
|
||||
* Get the avatar url and dimensions
|
||||
*
|
||||
* @param array $row User data or group data that has been cleaned with
|
||||
* \phpbb\avatar\manager::clean_row
|
||||
* @return array Avatar data, must have keys src, width and height, e.g.
|
||||
* ['src' => '', 'width' => 0, 'height' => 0]
|
||||
*/
|
||||
public function get_data($row);
|
||||
|
||||
/**
|
||||
* Returns custom html if it is needed for displaying this avatar
|
||||
*
|
||||
* @param \phpbb\user $user phpBB user object
|
||||
* @param array $row User data or group data that has been cleaned with
|
||||
* \phpbb\avatar\manager::clean_row
|
||||
* @param string $alt Alternate text for avatar image
|
||||
*
|
||||
* @return string HTML
|
||||
*/
|
||||
public function get_custom_html($user, $row, $alt = '');
|
||||
|
||||
/**
|
||||
* Prepare form for changing the settings of this avatar
|
||||
*
|
||||
* @param \phpbb\request\request $request Request object
|
||||
* @param \phpbb\template\template $template Template object
|
||||
* @param \phpbb\user $user User object
|
||||
* @param array $row User data or group data that has been cleaned with
|
||||
* \phpbb\avatar\manager::clean_row
|
||||
* @param array &$error Reference to an error array that is filled by this
|
||||
* function. Key values can either be a string with a language key or
|
||||
* an array that will be passed to vsprintf() with the language key in
|
||||
* the first array key.
|
||||
*
|
||||
* @return bool True if form has been successfully prepared
|
||||
*/
|
||||
public function prepare_form($request, $template, $user, $row, &$error);
|
||||
|
||||
/**
|
||||
* Prepare form for changing the acp settings of this avatar
|
||||
*
|
||||
* @param \phpbb\user $user phpBB user object
|
||||
*
|
||||
* @return array Array of configuration options as consumed by acp_board.
|
||||
* The setting for enabling/disabling the avatar will be handled by
|
||||
* the avatar manager.
|
||||
*/
|
||||
public function prepare_form_acp($user);
|
||||
|
||||
/**
|
||||
* Process form data
|
||||
*
|
||||
* @param \phpbb\request\request $request Request object
|
||||
* @param \phpbb\template\template $template Template object
|
||||
* @param \phpbb\user $user User object
|
||||
* @param array $row User data or group data that has been cleaned with
|
||||
* \phpbb\avatar\manager::clean_row
|
||||
* @param array &$error Reference to an error array that is filled by this
|
||||
* function. Key values can either be a string with a language key or
|
||||
* an array that will be passed to vsprintf() with the language key in
|
||||
* the first array key.
|
||||
*
|
||||
* @return array Array containing the avatar data as follows:
|
||||
* ['avatar'], ['avatar_width'], ['avatar_height']
|
||||
*/
|
||||
public function process_form($request, $template, $user, $row, &$error);
|
||||
|
||||
/**
|
||||
* Delete avatar
|
||||
*
|
||||
* @param array $row User data or group data that has been cleaned with
|
||||
* \phpbb\avatar\manager::clean_row
|
||||
*
|
||||
* @return bool True if avatar has been deleted or there is no need to delete,
|
||||
* i.e. when the avatar is not hosted locally.
|
||||
*/
|
||||
public function delete($row);
|
||||
|
||||
/**
|
||||
* Get the avatar driver's template name
|
||||
*
|
||||
* @return string Avatar driver's template name
|
||||
*/
|
||||
public function get_template_name();
|
||||
|
||||
/**
|
||||
* Get the avatar driver's template name (ACP)
|
||||
*
|
||||
* @return string Avatar driver's template name
|
||||
*/
|
||||
public function get_acp_template_name();
|
||||
}
|
||||
198
phpbb/avatar/driver/gravatar.php
Normal file
198
phpbb/avatar/driver/gravatar.php
Normal file
@@ -0,0 +1,198 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\avatar\driver;
|
||||
|
||||
/**
|
||||
* Handles avatars hosted at gravatar.com
|
||||
*/
|
||||
class gravatar extends \phpbb\avatar\driver\driver
|
||||
{
|
||||
/**
|
||||
* The URL for the gravatar service
|
||||
*/
|
||||
const GRAVATAR_URL = '//secure.gravatar.com/avatar/';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get_data($row)
|
||||
{
|
||||
return array(
|
||||
'src' => $row['avatar'],
|
||||
'width' => $row['avatar_width'],
|
||||
'height' => $row['avatar_height'],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get_custom_html($user, $row, $alt = '')
|
||||
{
|
||||
return '<img src="' . $this->get_gravatar_url($row) . '" ' .
|
||||
($row['avatar_width'] ? ('width="' . $row['avatar_width'] . '" ') : '') .
|
||||
($row['avatar_height'] ? ('height="' . $row['avatar_height'] . '" ') : '') .
|
||||
'alt="' . ((!empty($user->lang[$alt])) ? $user->lang[$alt] : $alt) . '" />';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function prepare_form($request, $template, $user, $row, &$error)
|
||||
{
|
||||
$template->assign_vars(array(
|
||||
'AVATAR_GRAVATAR_WIDTH' => (($row['avatar_type'] == $this->get_name() || $row['avatar_type'] == 'gravatar') && $row['avatar_width']) ? $row['avatar_width'] : $request->variable('avatar_gravatar_width', ''),
|
||||
'AVATAR_GRAVATAR_HEIGHT' => (($row['avatar_type'] == $this->get_name() || $row['avatar_type'] == 'gravatar') && $row['avatar_height']) ? $row['avatar_height'] : $request->variable('avatar_gravatar_width', ''),
|
||||
'AVATAR_GRAVATAR_EMAIL' => (($row['avatar_type'] == $this->get_name() || $row['avatar_type'] == 'gravatar') && $row['avatar']) ? $row['avatar'] : '',
|
||||
));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function process_form($request, $template, $user, $row, &$error)
|
||||
{
|
||||
$row['avatar'] = $request->variable('avatar_gravatar_email', '');
|
||||
$row['avatar_width'] = $request->variable('avatar_gravatar_width', 0);
|
||||
$row['avatar_height'] = $request->variable('avatar_gravatar_height', 0);
|
||||
|
||||
if (empty($row['avatar']))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!function_exists('validate_data'))
|
||||
{
|
||||
require($this->phpbb_root_path . 'includes/functions_user.' . $this->php_ext);
|
||||
}
|
||||
|
||||
$validate_array = validate_data(
|
||||
array(
|
||||
'email' => $row['avatar'],
|
||||
),
|
||||
array(
|
||||
'email' => array(
|
||||
array('string', false, 6, 60),
|
||||
array('email'),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
$error = array_merge($error, $validate_array);
|
||||
|
||||
if (!empty($error))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get image dimensions if they are not set
|
||||
if ($row['avatar_width'] <= 0 || $row['avatar_height'] <= 0)
|
||||
{
|
||||
/**
|
||||
* default to the minimum of the maximum allowed avatar size if the size
|
||||
* is not or only partially entered
|
||||
*/
|
||||
$row['avatar_width'] = $row['avatar_height'] = min($this->config['avatar_max_width'], $this->config['avatar_max_height']);
|
||||
$url = $this->get_gravatar_url($row);
|
||||
|
||||
if (($row['avatar_width'] <= 0 || $row['avatar_height'] <= 0) && (($image_data = $this->imagesize->getImageSize($url)) === false))
|
||||
{
|
||||
$error[] = 'UNABLE_GET_IMAGE_SIZE';
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!empty($image_data) && ($image_data['width'] <= 0 || $image_data['width'] <= 0))
|
||||
{
|
||||
$error[] = 'AVATAR_NO_SIZE';
|
||||
return false;
|
||||
}
|
||||
|
||||
$row['avatar_width'] = ($row['avatar_width'] && $row['avatar_height']) ? $row['avatar_width'] : $image_data['width'];
|
||||
$row['avatar_height'] = ($row['avatar_width'] && $row['avatar_height']) ? $row['avatar_height'] : $image_data['height'];
|
||||
}
|
||||
|
||||
if ($row['avatar_width'] <= 0 || $row['avatar_height'] <= 0)
|
||||
{
|
||||
$error[] = 'AVATAR_NO_SIZE';
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->config['avatar_max_width'] || $this->config['avatar_max_height'])
|
||||
{
|
||||
if ($row['avatar_width'] > $this->config['avatar_max_width'] || $row['avatar_height'] > $this->config['avatar_max_height'])
|
||||
{
|
||||
$error[] = array('AVATAR_WRONG_SIZE', $this->config['avatar_min_width'], $this->config['avatar_min_height'], $this->config['avatar_max_width'], $this->config['avatar_max_height'], $row['avatar_width'], $row['avatar_height']);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->config['avatar_min_width'] || $this->config['avatar_min_height'])
|
||||
{
|
||||
if ($row['avatar_width'] < $this->config['avatar_min_width'] || $row['avatar_height'] < $this->config['avatar_min_height'])
|
||||
{
|
||||
$error[] = array('AVATAR_WRONG_SIZE', $this->config['avatar_min_width'], $this->config['avatar_min_height'], $this->config['avatar_max_width'], $this->config['avatar_max_height'], $row['avatar_width'], $row['avatar_height']);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return array(
|
||||
'avatar' => $row['avatar'],
|
||||
'avatar_width' => $row['avatar_width'],
|
||||
'avatar_height' => $row['avatar_height'],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get_template_name()
|
||||
{
|
||||
return 'ucp_avatar_options_gravatar.html';
|
||||
}
|
||||
|
||||
/**
|
||||
* Build gravatar URL for output on page
|
||||
*
|
||||
* @param array $row User data or group data that has been cleaned with
|
||||
* \phpbb\avatar\manager::clean_row
|
||||
* @return string Gravatar URL
|
||||
*/
|
||||
protected function get_gravatar_url($row)
|
||||
{
|
||||
global $phpbb_dispatcher;
|
||||
|
||||
$url = self::GRAVATAR_URL;
|
||||
$url .= md5(strtolower(trim($row['avatar'])));
|
||||
|
||||
if ($row['avatar_width'] || $row['avatar_height'])
|
||||
{
|
||||
$url .= '?s=' . max($row['avatar_width'], $row['avatar_height']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify gravatar url
|
||||
*
|
||||
* @event core.get_gravatar_url_after
|
||||
* @var string row User data or group data
|
||||
* @var string url Gravatar URL
|
||||
* @since 3.1.7-RC1
|
||||
*/
|
||||
$vars = array('row', 'url');
|
||||
extract($phpbb_dispatcher->trigger_event('core.get_gravatar_url_after', compact($vars)));
|
||||
|
||||
return $url;
|
||||
}
|
||||
}
|
||||
207
phpbb/avatar/driver/local.php
Normal file
207
phpbb/avatar/driver/local.php
Normal file
@@ -0,0 +1,207 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\avatar\driver;
|
||||
|
||||
/**
|
||||
* Handles avatars selected from the board gallery
|
||||
*/
|
||||
class local extends \phpbb\avatar\driver\driver
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get_data($row)
|
||||
{
|
||||
$root_path = (defined('PHPBB_USE_BOARD_URL_PATH') && PHPBB_USE_BOARD_URL_PATH) ? generate_board_url() . '/' : $this->path_helper->get_web_root_path();
|
||||
|
||||
return array(
|
||||
'src' => $root_path . $this->config['avatar_gallery_path'] . '/' . $row['avatar'],
|
||||
'width' => $row['avatar_width'],
|
||||
'height' => $row['avatar_height'],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function prepare_form($request, $template, $user, $row, &$error)
|
||||
{
|
||||
$avatar_list = $this->get_avatar_list($user);
|
||||
$category = $request->variable('avatar_local_cat', key($avatar_list));
|
||||
|
||||
foreach ($avatar_list as $cat => $null)
|
||||
{
|
||||
if (!empty($avatar_list[$cat]))
|
||||
{
|
||||
$template->assign_block_vars('avatar_local_cats', array(
|
||||
'NAME' => $cat,
|
||||
'SELECTED' => ($cat == $category),
|
||||
));
|
||||
}
|
||||
|
||||
if ($cat != $category)
|
||||
{
|
||||
unset($avatar_list[$cat]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($avatar_list[$category]))
|
||||
{
|
||||
$template->assign_vars(array(
|
||||
'AVATAR_LOCAL_SHOW' => true,
|
||||
));
|
||||
|
||||
$table_cols = isset($row['avatar_gallery_cols']) ? $row['avatar_gallery_cols'] : 4;
|
||||
$row_count = $col_count = $avatar_pos = 0;
|
||||
$avatar_count = count($avatar_list[$category]);
|
||||
|
||||
reset($avatar_list[$category]);
|
||||
|
||||
while ($avatar_pos < $avatar_count)
|
||||
{
|
||||
$img = current($avatar_list[$category]);
|
||||
next($avatar_list[$category]);
|
||||
|
||||
if ($col_count == 0)
|
||||
{
|
||||
++$row_count;
|
||||
$template->assign_block_vars('avatar_local_row', array(
|
||||
));
|
||||
}
|
||||
|
||||
$template->assign_block_vars('avatar_local_row.avatar_local_col', array(
|
||||
'AVATAR_IMAGE' => $this->phpbb_root_path . $this->config['avatar_gallery_path'] . '/' . $img['file'],
|
||||
'AVATAR_NAME' => $img['name'],
|
||||
'AVATAR_FILE' => $img['filename'],
|
||||
'CHECKED' => $img['file'] === $row['avatar'],
|
||||
));
|
||||
|
||||
$template->assign_block_vars('avatar_local_row.avatar_local_option', array(
|
||||
'AVATAR_FILE' => $img['filename'],
|
||||
'S_OPTIONS_AVATAR' => $img['filename'],
|
||||
'CHECKED' => $img['file'] === $row['avatar'],
|
||||
));
|
||||
|
||||
$col_count = ($col_count + 1) % $table_cols;
|
||||
|
||||
++$avatar_pos;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function prepare_form_acp($user)
|
||||
{
|
||||
return array(
|
||||
'avatar_gallery_path' => array('lang' => 'AVATAR_GALLERY_PATH', 'validate' => 'rpath', 'type' => 'text:20:255', 'explain' => true),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function process_form($request, $template, $user, $row, &$error)
|
||||
{
|
||||
$avatar_list = $this->get_avatar_list($user);
|
||||
$category = $request->variable('avatar_local_cat', '');
|
||||
|
||||
$file = $request->variable('avatar_local_file', '');
|
||||
|
||||
if (empty($category) || empty($file))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isset($avatar_list[$category][urldecode($file)]))
|
||||
{
|
||||
$error[] = 'AVATAR_URL_NOT_FOUND';
|
||||
return false;
|
||||
}
|
||||
|
||||
return array(
|
||||
'avatar' => ($category != $user->lang['NO_AVATAR_CATEGORY']) ? $category . '/' . $file : $file,
|
||||
'avatar_width' => $avatar_list[$category][urldecode($file)]['width'],
|
||||
'avatar_height' => $avatar_list[$category][urldecode($file)]['height'],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get_template_name()
|
||||
{
|
||||
return 'ucp_avatar_options_local.html';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of avatars that are locally available
|
||||
* Results get cached for 24 hours (86400 seconds)
|
||||
*
|
||||
* @param \phpbb\user $user User object
|
||||
*
|
||||
* @return array Array containing the locally available avatars
|
||||
*/
|
||||
protected function get_avatar_list($user)
|
||||
{
|
||||
$avatar_list = ($this->cache == null) ? false : $this->cache->get('_avatar_local_list_' . $user->data['user_lang']);
|
||||
|
||||
if ($avatar_list === false)
|
||||
{
|
||||
$avatar_list = array();
|
||||
$path = $this->phpbb_root_path . $this->config['avatar_gallery_path'];
|
||||
|
||||
$iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path, \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::UNIX_PATHS), \RecursiveIteratorIterator::SELF_FIRST);
|
||||
foreach ($iterator as $file_info)
|
||||
{
|
||||
$file_path = $file_info->getPath();
|
||||
$image = $file_info->getFilename();
|
||||
|
||||
// Match all images in the gallery folder
|
||||
if (preg_match('#^[^&\'"<>]+\.(?:' . implode('|', $this->allowed_extensions) . ')$#i', $image) && is_file($file_path . '/' . $image))
|
||||
{
|
||||
$dims = $this->imagesize->getImageSize($file_path . '/' . $image);
|
||||
|
||||
if ($dims === false)
|
||||
{
|
||||
$dims = array(0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
$dims = array($dims['width'], $dims['height']);
|
||||
}
|
||||
$cat = ($path == $file_path) ? $user->lang['NO_AVATAR_CATEGORY'] : str_replace("$path/", '', $file_path);
|
||||
$avatar_list[$cat][$image] = array(
|
||||
'file' => ($cat != $user->lang['NO_AVATAR_CATEGORY']) ? str_replace('%2F', '/', rawurlencode($cat)) . '/' . rawurlencode($image) : rawurlencode($image),
|
||||
'filename' => rawurlencode($image),
|
||||
'name' => ucfirst(str_replace('_', ' ', preg_replace('#^(.*)\..*$#', '\1', $image))),
|
||||
'width' => $dims[0],
|
||||
'height' => $dims[1],
|
||||
);
|
||||
}
|
||||
}
|
||||
ksort($avatar_list);
|
||||
|
||||
if ($this->cache != null)
|
||||
{
|
||||
$this->cache->put('_avatar_local_list_' . $user->data['user_lang'], $avatar_list, 86400);
|
||||
}
|
||||
}
|
||||
|
||||
return $avatar_list;
|
||||
}
|
||||
}
|
||||
216
phpbb/avatar/driver/remote.php
Normal file
216
phpbb/avatar/driver/remote.php
Normal file
@@ -0,0 +1,216 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\avatar\driver;
|
||||
|
||||
/**
|
||||
* Handles avatars hosted remotely
|
||||
*/
|
||||
class remote extends \phpbb\avatar\driver\driver
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get_data($row)
|
||||
{
|
||||
return array(
|
||||
'src' => $row['avatar'],
|
||||
'width' => $row['avatar_width'],
|
||||
'height' => $row['avatar_height'],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function prepare_form($request, $template, $user, $row, &$error)
|
||||
{
|
||||
$template->assign_vars(array(
|
||||
'AVATAR_REMOTE_WIDTH' => ((in_array($row['avatar_type'], array(AVATAR_REMOTE, $this->get_name(), 'remote'))) && $row['avatar_width']) ? $row['avatar_width'] : $request->variable('avatar_remote_width', ''),
|
||||
'AVATAR_REMOTE_HEIGHT' => ((in_array($row['avatar_type'], array(AVATAR_REMOTE, $this->get_name(), 'remote'))) && $row['avatar_height']) ? $row['avatar_height'] : $request->variable('avatar_remote_width', ''),
|
||||
'AVATAR_REMOTE_URL' => ((in_array($row['avatar_type'], array(AVATAR_REMOTE, $this->get_name(), 'remote'))) && $row['avatar']) ? $row['avatar'] : '',
|
||||
));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function process_form($request, $template, $user, $row, &$error)
|
||||
{
|
||||
$url = $request->variable('avatar_remote_url', '');
|
||||
$width = $request->variable('avatar_remote_width', 0);
|
||||
$height = $request->variable('avatar_remote_height', 0);
|
||||
|
||||
if (empty($url))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!preg_match('#^(http|https|ftp)://#i', $url))
|
||||
{
|
||||
$url = 'http://' . $url;
|
||||
}
|
||||
|
||||
if (!function_exists('validate_data'))
|
||||
{
|
||||
require($this->phpbb_root_path . 'includes/functions_user.' . $this->php_ext);
|
||||
}
|
||||
|
||||
$validate_array = validate_data(
|
||||
array(
|
||||
'url' => $url,
|
||||
),
|
||||
array(
|
||||
'url' => array('string', true, 5, 255),
|
||||
)
|
||||
);
|
||||
|
||||
$error = array_merge($error, $validate_array);
|
||||
|
||||
if (!empty($error))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if this url looks alright
|
||||
// Do not allow specifying the port (see RFC 3986) or IP addresses
|
||||
if (!preg_match('#^(http|https|ftp)://(?:(.*?\.)*?[a-z0-9\-]+?\.[a-z]{2,4}|(?:\d{1,3}\.){3,5}\d{1,3}):?([0-9]*?).*?\.('. implode('|', $this->allowed_extensions) . ')$#i', $url) ||
|
||||
preg_match('@^(http|https|ftp)://[^/:?#]+:[0-9]+[/:?#]@i', $url) ||
|
||||
preg_match('#^(http|https|ftp)://(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])#i', $url) ||
|
||||
preg_match('#^(http|https|ftp)://(?:(?:(?:[\dA-F]{1,4}:){6}(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:::(?:[\dA-F]{1,4}:){0,5}(?:[\dA-F]{1,4}(?::[\dA-F]{1,4})?|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:(?:[\dA-F]{1,4}:):(?:[\dA-F]{1,4}:){4}(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:(?:[\dA-F]{1,4}:){1,2}:(?:[\dA-F]{1,4}:){3}(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:(?:[\dA-F]{1,4}:){1,3}:(?:[\dA-F]{1,4}:){2}(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:(?:[\dA-F]{1,4}:){1,4}:(?:[\dA-F]{1,4}:)(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:(?:[\dA-F]{1,4}:){1,5}:(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:(?:[\dA-F]{1,4}:){1,6}:[\dA-F]{1,4})|(?:(?:[\dA-F]{1,4}:){1,7}:)|(?:::))#i', $url))
|
||||
{
|
||||
$error[] = 'AVATAR_URL_INVALID';
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get image dimensions
|
||||
if (($width <= 0 || $height <= 0) && (($image_data = $this->imagesize->getImageSize($url)) === false))
|
||||
{
|
||||
$error[] = 'UNABLE_GET_IMAGE_SIZE';
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!empty($image_data) && ($image_data['width'] <= 0 || $image_data['height'] <= 0))
|
||||
{
|
||||
$error[] = 'AVATAR_NO_SIZE';
|
||||
return false;
|
||||
}
|
||||
|
||||
$width = ($width && $height) ? $width : $image_data['width'];
|
||||
$height = ($width && $height) ? $height : $image_data['height'];
|
||||
|
||||
if ($width <= 0 || $height <= 0)
|
||||
{
|
||||
$error[] = 'AVATAR_NO_SIZE';
|
||||
return false;
|
||||
}
|
||||
|
||||
$types = \phpbb\files\upload::image_types();
|
||||
$extension = strtolower(\phpbb\files\filespec::get_extension($url));
|
||||
|
||||
// Check if this is actually an image
|
||||
if ($file_stream = @fopen($url, 'r'))
|
||||
{
|
||||
// Timeout after 1 second
|
||||
stream_set_timeout($file_stream, 1);
|
||||
// read some data to ensure headers are present
|
||||
fread($file_stream, 1024);
|
||||
$meta = stream_get_meta_data($file_stream);
|
||||
|
||||
if (isset($meta['wrapper_data']['headers']) && is_array($meta['wrapper_data']['headers']))
|
||||
{
|
||||
$headers = $meta['wrapper_data']['headers'];
|
||||
}
|
||||
else if (isset($meta['wrapper_data']) && is_array($meta['wrapper_data']))
|
||||
{
|
||||
$headers = $meta['wrapper_data'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$headers = array();
|
||||
}
|
||||
|
||||
foreach ($headers as $header)
|
||||
{
|
||||
$header = preg_split('/ /', $header, 2);
|
||||
if (strtr(strtolower(trim($header[0], ':')), '_', '-') === 'content-type')
|
||||
{
|
||||
if (strpos($header[1], 'image/') !== 0)
|
||||
{
|
||||
$error[] = 'AVATAR_URL_INVALID';
|
||||
fclose($file_stream);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
fclose($file_stream);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$error[] = 'AVATAR_URL_INVALID';
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!empty($image_data) && (!isset($types[$image_data['type']]) || !in_array($extension, $types[$image_data['type']])))
|
||||
{
|
||||
if (!isset($types[$image_data['type']]))
|
||||
{
|
||||
$error[] = 'UNABLE_GET_IMAGE_SIZE';
|
||||
}
|
||||
else
|
||||
{
|
||||
$error[] = array('IMAGE_FILETYPE_MISMATCH', $types[$image_data['type']][0], $extension);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->config['avatar_max_width'] || $this->config['avatar_max_height'])
|
||||
{
|
||||
if ($width > $this->config['avatar_max_width'] || $height > $this->config['avatar_max_height'])
|
||||
{
|
||||
$error[] = array('AVATAR_WRONG_SIZE', $this->config['avatar_min_width'], $this->config['avatar_min_height'], $this->config['avatar_max_width'], $this->config['avatar_max_height'], $width, $height);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->config['avatar_min_width'] || $this->config['avatar_min_height'])
|
||||
{
|
||||
if ($width < $this->config['avatar_min_width'] || $height < $this->config['avatar_min_height'])
|
||||
{
|
||||
$error[] = array('AVATAR_WRONG_SIZE', $this->config['avatar_min_width'], $this->config['avatar_min_height'], $this->config['avatar_max_width'], $this->config['avatar_max_height'], $width, $height);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return array(
|
||||
'avatar' => $url,
|
||||
'avatar_width' => $width,
|
||||
'avatar_height' => $height,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get_template_name()
|
||||
{
|
||||
return 'ucp_avatar_options_remote.html';
|
||||
}
|
||||
}
|
||||
331
phpbb/avatar/driver/upload.php
Normal file
331
phpbb/avatar/driver/upload.php
Normal file
@@ -0,0 +1,331 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\avatar\driver;
|
||||
|
||||
/**
|
||||
* Handles avatars uploaded to the board
|
||||
*/
|
||||
class upload extends \phpbb\avatar\driver\driver
|
||||
{
|
||||
/**
|
||||
* @var \phpbb\filesystem\filesystem_interface
|
||||
*/
|
||||
protected $filesystem;
|
||||
|
||||
/**
|
||||
* @var \phpbb\event\dispatcher_interface
|
||||
*/
|
||||
protected $dispatcher;
|
||||
|
||||
/**
|
||||
* @var \phpbb\files\factory
|
||||
*/
|
||||
protected $files_factory;
|
||||
|
||||
/**
|
||||
* Construct a driver object
|
||||
*
|
||||
* @param \phpbb\config\config $config phpBB configuration
|
||||
* @param string $phpbb_root_path Path to the phpBB root
|
||||
* @param string $php_ext PHP file extension
|
||||
* @param \phpbb\filesystem\filesystem_interface $filesystem phpBB filesystem helper
|
||||
* @param \phpbb\path_helper $path_helper phpBB path helper
|
||||
* @param \phpbb\event\dispatcher_interface $dispatcher phpBB Event dispatcher object
|
||||
* @param \phpbb\files\factory $files_factory File classes factory
|
||||
* @param \phpbb\cache\driver\driver_interface $cache Cache driver
|
||||
*/
|
||||
public function __construct(\phpbb\config\config $config, $phpbb_root_path, $php_ext, \phpbb\filesystem\filesystem_interface $filesystem, \phpbb\path_helper $path_helper, \phpbb\event\dispatcher_interface $dispatcher, \phpbb\files\factory $files_factory, \phpbb\cache\driver\driver_interface $cache = null)
|
||||
{
|
||||
$this->config = $config;
|
||||
$this->phpbb_root_path = $phpbb_root_path;
|
||||
$this->php_ext = $php_ext;
|
||||
$this->filesystem = $filesystem;
|
||||
$this->path_helper = $path_helper;
|
||||
$this->dispatcher = $dispatcher;
|
||||
$this->files_factory = $files_factory;
|
||||
$this->cache = $cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get_data($row)
|
||||
{
|
||||
$root_path = (defined('PHPBB_USE_BOARD_URL_PATH') && PHPBB_USE_BOARD_URL_PATH) ? generate_board_url() . '/' : $this->path_helper->get_web_root_path();
|
||||
|
||||
return array(
|
||||
'src' => $root_path . 'download/file.' . $this->php_ext . '?avatar=' . $row['avatar'],
|
||||
'width' => $row['avatar_width'],
|
||||
'height' => $row['avatar_height'],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function prepare_form($request, $template, $user, $row, &$error)
|
||||
{
|
||||
if (!$this->can_upload())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$template->assign_vars(array(
|
||||
'S_UPLOAD_AVATAR_URL' => ($this->config['allow_avatar_remote_upload']) ? true : false,
|
||||
'AVATAR_UPLOAD_SIZE' => $this->config['avatar_filesize'],
|
||||
));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function process_form($request, $template, $user, $row, &$error)
|
||||
{
|
||||
if (!$this->can_upload())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @var \phpbb\files\upload $upload */
|
||||
$upload = $this->files_factory->get('upload')
|
||||
->set_error_prefix('AVATAR_')
|
||||
->set_allowed_extensions($this->allowed_extensions)
|
||||
->set_max_filesize($this->config['avatar_filesize'])
|
||||
->set_allowed_dimensions(
|
||||
$this->config['avatar_min_width'],
|
||||
$this->config['avatar_min_height'],
|
||||
$this->config['avatar_max_width'],
|
||||
$this->config['avatar_max_height'])
|
||||
->set_disallowed_content((isset($this->config['mime_triggers']) ? explode('|', $this->config['mime_triggers']) : false));
|
||||
|
||||
$url = $request->variable('avatar_upload_url', '');
|
||||
$upload_file = $request->file('avatar_upload_file');
|
||||
|
||||
if (!empty($upload_file['name']))
|
||||
{
|
||||
$file = $upload->handle_upload('files.types.form', 'avatar_upload_file');
|
||||
}
|
||||
else if (!empty($this->config['allow_avatar_remote_upload']) && !empty($url))
|
||||
{
|
||||
if (!preg_match('#^(http|https|ftp)://#i', $url))
|
||||
{
|
||||
$url = 'http://' . $url;
|
||||
}
|
||||
|
||||
if (!function_exists('validate_data'))
|
||||
{
|
||||
require($this->phpbb_root_path . 'includes/functions_user.' . $this->php_ext);
|
||||
}
|
||||
|
||||
$validate_array = validate_data(
|
||||
array(
|
||||
'url' => $url,
|
||||
),
|
||||
array(
|
||||
'url' => array('string', true, 5, 255),
|
||||
)
|
||||
);
|
||||
|
||||
$error = array_merge($error, $validate_array);
|
||||
|
||||
if (!empty($error))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Do not allow specifying the port (see RFC 3986) or IP addresses
|
||||
// remote_upload() will do its own check for allowed filetypes
|
||||
if (!preg_match('#^(http|https|ftp)://(?:(.*?\.)*?[a-z0-9\-]+?\.[a-z]{2,4}|(?:\d{1,3}\.){3,5}\d{1,3}):?([0-9]*?).*?\.('. implode('|', $this->allowed_extensions) . ')$#i', $url) ||
|
||||
preg_match('@^(http|https|ftp)://[^/:?#]+:[0-9]+[/:?#]@i', $url) ||
|
||||
preg_match('#^(http|https|ftp)://(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])#i', $url) ||
|
||||
preg_match('#^(http|https|ftp)://(?:(?:(?:[\dA-F]{1,4}:){6}(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:::(?:[\dA-F]{1,4}:){0,5}(?:[\dA-F]{1,4}(?::[\dA-F]{1,4})?|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:(?:[\dA-F]{1,4}:):(?:[\dA-F]{1,4}:){4}(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:(?:[\dA-F]{1,4}:){1,2}:(?:[\dA-F]{1,4}:){3}(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:(?:[\dA-F]{1,4}:){1,3}:(?:[\dA-F]{1,4}:){2}(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:(?:[\dA-F]{1,4}:){1,4}:(?:[\dA-F]{1,4}:)(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:(?:[\dA-F]{1,4}:){1,5}:(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:(?:[\dA-F]{1,4}:){1,6}:[\dA-F]{1,4})|(?:(?:[\dA-F]{1,4}:){1,7}:)|(?:::))#i', $url))
|
||||
{
|
||||
$error[] = 'AVATAR_URL_INVALID';
|
||||
return false;
|
||||
}
|
||||
|
||||
$file = $upload->handle_upload('files.types.remote', $url);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$prefix = $this->config['avatar_salt'] . '_';
|
||||
$file->clean_filename('avatar', $prefix, $row['id']);
|
||||
|
||||
// If there was an error during upload, then abort operation
|
||||
if (count($file->error))
|
||||
{
|
||||
$file->remove();
|
||||
$error = $file->error;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Calculate new destination
|
||||
$destination = $this->config['avatar_path'];
|
||||
|
||||
// Adjust destination path (no trailing slash)
|
||||
if (substr($destination, -1, 1) == '/' || substr($destination, -1, 1) == '\\')
|
||||
{
|
||||
$destination = substr($destination, 0, -1);
|
||||
}
|
||||
|
||||
$destination = str_replace(array('../', '..\\', './', '.\\'), '', $destination);
|
||||
if ($destination && ($destination[0] == '/' || $destination[0] == "\\"))
|
||||
{
|
||||
$destination = '';
|
||||
}
|
||||
|
||||
$filedata = array(
|
||||
'filename' => $file->get('filename'),
|
||||
'filesize' => $file->get('filesize'),
|
||||
'mimetype' => $file->get('mimetype'),
|
||||
'extension' => $file->get('extension'),
|
||||
'physical_filename' => $file->get('realname'),
|
||||
'real_filename' => $file->get('uploadname'),
|
||||
);
|
||||
|
||||
/**
|
||||
* Before moving new file in place (and eventually overwriting the existing avatar with the newly uploaded avatar)
|
||||
*
|
||||
* @event core.avatar_driver_upload_move_file_before
|
||||
* @var array filedata Array containing uploaded file data
|
||||
* @var \phpbb\files\filespec file Instance of filespec class
|
||||
* @var string destination Destination directory where the file is going to be moved
|
||||
* @var string prefix Prefix for the avatar filename
|
||||
* @var array row Array with avatar row data
|
||||
* @var array error Array of errors, if filled in by this event file will not be moved
|
||||
* @since 3.1.6-RC1
|
||||
* @changed 3.1.9-RC1 Added filedata
|
||||
* @changed 3.2.3-RC1 Added file
|
||||
*/
|
||||
$vars = array(
|
||||
'filedata',
|
||||
'file',
|
||||
'destination',
|
||||
'prefix',
|
||||
'row',
|
||||
'error',
|
||||
);
|
||||
extract($this->dispatcher->trigger_event('core.avatar_driver_upload_move_file_before', compact($vars)));
|
||||
|
||||
unset($filedata);
|
||||
|
||||
if (!count($error))
|
||||
{
|
||||
// Move file and overwrite any existing image
|
||||
$file->move_file($destination, true);
|
||||
}
|
||||
|
||||
// If there was an error during move, then clean up leftovers
|
||||
$error = array_merge($error, $file->error);
|
||||
if (count($error))
|
||||
{
|
||||
$file->remove();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Delete current avatar if not overwritten
|
||||
$ext = substr(strrchr($row['avatar'], '.'), 1);
|
||||
if ($ext && $ext !== $file->get('extension'))
|
||||
{
|
||||
$this->delete($row);
|
||||
}
|
||||
|
||||
return array(
|
||||
'avatar' => $row['id'] . '_' . time() . '.' . $file->get('extension'),
|
||||
'avatar_width' => $file->get('width'),
|
||||
'avatar_height' => $file->get('height'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function prepare_form_acp($user)
|
||||
{
|
||||
return array(
|
||||
'allow_avatar_remote_upload'=> array('lang' => 'ALLOW_REMOTE_UPLOAD', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
|
||||
'avatar_filesize' => array('lang' => 'MAX_FILESIZE', 'validate' => 'int:0', 'type' => 'number:0', 'explain' => true, 'append' => ' ' . $user->lang['BYTES']),
|
||||
'avatar_path' => array('lang' => 'AVATAR_STORAGE_PATH', 'validate' => 'rpath', 'type' => 'text:20:255', 'explain' => true),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function delete($row)
|
||||
{
|
||||
|
||||
$error = array();
|
||||
$destination = $this->config['avatar_path'];
|
||||
$prefix = $this->config['avatar_salt'] . '_';
|
||||
$ext = substr(strrchr($row['avatar'], '.'), 1);
|
||||
$filename = $this->phpbb_root_path . $destination . '/' . $prefix . $row['id'] . '.' . $ext;
|
||||
|
||||
/**
|
||||
* Before deleting an existing avatar
|
||||
*
|
||||
* @event core.avatar_driver_upload_delete_before
|
||||
* @var string destination Destination directory where the file is going to be deleted
|
||||
* @var string prefix Prefix for the avatar filename
|
||||
* @var array row Array with avatar row data
|
||||
* @var array error Array of errors, if filled in by this event file will not be deleted
|
||||
* @since 3.1.6-RC1
|
||||
*/
|
||||
$vars = array(
|
||||
'destination',
|
||||
'prefix',
|
||||
'row',
|
||||
'error',
|
||||
);
|
||||
extract($this->dispatcher->trigger_event('core.avatar_driver_upload_delete_before', compact($vars)));
|
||||
|
||||
if (!count($error) && $this->filesystem->exists($filename))
|
||||
{
|
||||
try
|
||||
{
|
||||
$this->filesystem->remove($filename);
|
||||
return true;
|
||||
}
|
||||
catch (\phpbb\filesystem\exception\filesystem_exception $e)
|
||||
{
|
||||
// Fail is covered by return statement below
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get_template_name()
|
||||
{
|
||||
return 'ucp_avatar_options_upload.html';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if user is able to upload an avatar
|
||||
*
|
||||
* @return bool True if user can upload, false if not
|
||||
*/
|
||||
protected function can_upload()
|
||||
{
|
||||
return ($this->filesystem->exists($this->phpbb_root_path . $this->config['avatar_path']) && $this->filesystem->is_writable($this->phpbb_root_path . $this->config['avatar_path']) && (@ini_get('file_uploads') || strtolower(@ini_get('file_uploads')) == 'on'));
|
||||
}
|
||||
}
|
||||
375
phpbb/avatar/manager.php
Normal file
375
phpbb/avatar/manager.php
Normal file
@@ -0,0 +1,375 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\avatar;
|
||||
|
||||
class manager
|
||||
{
|
||||
/**
|
||||
* phpBB configuration
|
||||
* @var \phpbb\config\config
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* phpBB event dispatcher
|
||||
* @var \phpbb\event\dispatcher_interface
|
||||
*/
|
||||
protected $phpbb_dispatcher;
|
||||
|
||||
/**
|
||||
* Array that contains a list of enabled drivers
|
||||
* @var array
|
||||
*/
|
||||
static protected $enabled_drivers = false;
|
||||
|
||||
/**
|
||||
* Array that contains all available avatar drivers which are passed via the
|
||||
* service container
|
||||
* @var array
|
||||
*/
|
||||
protected $avatar_drivers;
|
||||
|
||||
/**
|
||||
* Default avatar data row
|
||||
* @var array
|
||||
*/
|
||||
static protected $default_row = array(
|
||||
'avatar' => '',
|
||||
'avatar_type' => '',
|
||||
'avatar_width' => 0,
|
||||
'avatar_height' => 0,
|
||||
);
|
||||
|
||||
/**
|
||||
* Construct an avatar manager object
|
||||
*
|
||||
* @param \phpbb\config\config $config phpBB configuration
|
||||
* @param \phpbb\event\dispatcher_interface $phpbb_dispatcher phpBB event dispatcher
|
||||
* @param array $avatar_drivers Avatar drivers passed via the service container
|
||||
*/
|
||||
public function __construct(\phpbb\config\config $config, \phpbb\event\dispatcher_interface $phpbb_dispatcher, $avatar_drivers)
|
||||
{
|
||||
$this->config = $config;
|
||||
$this->phpbb_dispatcher = $phpbb_dispatcher;
|
||||
$this->register_avatar_drivers($avatar_drivers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register avatar drivers
|
||||
*
|
||||
* @param array $avatar_drivers Service collection of avatar drivers
|
||||
*/
|
||||
protected function register_avatar_drivers($avatar_drivers)
|
||||
{
|
||||
if (!empty($avatar_drivers))
|
||||
{
|
||||
foreach ($avatar_drivers as $driver)
|
||||
{
|
||||
$this->avatar_drivers[$driver->get_name()] = $driver;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the driver object specified by the avatar type
|
||||
*
|
||||
* @param string $avatar_type Avatar type; by default an avatar's service container name
|
||||
* @param bool $load_enabled Load only enabled avatars
|
||||
*
|
||||
* @return object Avatar driver object
|
||||
*/
|
||||
public function get_driver($avatar_type, $load_enabled = true)
|
||||
{
|
||||
if (self::$enabled_drivers === false)
|
||||
{
|
||||
$this->load_enabled_drivers();
|
||||
}
|
||||
|
||||
$avatar_drivers = ($load_enabled) ? self::$enabled_drivers : $this->get_all_drivers();
|
||||
|
||||
// Legacy stuff...
|
||||
switch ($avatar_type)
|
||||
{
|
||||
case AVATAR_GALLERY:
|
||||
$avatar_type = 'avatar.driver.local';
|
||||
break;
|
||||
case AVATAR_UPLOAD:
|
||||
$avatar_type = 'avatar.driver.upload';
|
||||
break;
|
||||
case AVATAR_REMOTE:
|
||||
$avatar_type = 'avatar.driver.remote';
|
||||
break;
|
||||
}
|
||||
|
||||
if (!isset($avatar_drivers[$avatar_type]))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* There is no need to handle invalid avatar types as the following code
|
||||
* will cause a ServiceNotFoundException if the type does not exist
|
||||
*/
|
||||
$driver = $this->avatar_drivers[$avatar_type];
|
||||
|
||||
return $driver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the list of enabled drivers
|
||||
* This is executed once and fills self::$enabled_drivers
|
||||
*/
|
||||
protected function load_enabled_drivers()
|
||||
{
|
||||
if (!empty($this->avatar_drivers))
|
||||
{
|
||||
self::$enabled_drivers = array();
|
||||
foreach ($this->avatar_drivers as $driver)
|
||||
{
|
||||
if ($this->is_enabled($driver))
|
||||
{
|
||||
self::$enabled_drivers[$driver->get_name()] = $driver->get_name();
|
||||
}
|
||||
}
|
||||
asort(self::$enabled_drivers);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all avatar drivers
|
||||
*
|
||||
* As this function will only be called in the ACP avatar settings page, it
|
||||
* doesn't make much sense to cache the list of all avatar drivers like the
|
||||
* list of the enabled drivers.
|
||||
*
|
||||
* @return array Array containing a list of all avatar drivers
|
||||
*/
|
||||
public function get_all_drivers()
|
||||
{
|
||||
$drivers = array();
|
||||
|
||||
if (!empty($this->avatar_drivers))
|
||||
{
|
||||
foreach ($this->avatar_drivers as $driver)
|
||||
{
|
||||
$drivers[$driver->get_name()] = $driver->get_name();
|
||||
}
|
||||
asort($drivers);
|
||||
}
|
||||
|
||||
return $drivers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of enabled avatar drivers
|
||||
*
|
||||
* @return array Array containing a list of the enabled avatar drivers
|
||||
*/
|
||||
public function get_enabled_drivers()
|
||||
{
|
||||
if (self::$enabled_drivers === false)
|
||||
{
|
||||
$this->load_enabled_drivers();
|
||||
}
|
||||
|
||||
return self::$enabled_drivers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Strip out user_, group_, or other prefixes from array keys
|
||||
*
|
||||
* @param array $row User data or group data
|
||||
* @param string $prefix Prefix of data keys (e.g. user), should not include the trailing underscore
|
||||
*
|
||||
* @return array User or group data with keys that have been
|
||||
* stripped from the preceding "user_" or "group_"
|
||||
* Also the group id is prefixed with g, when the prefix group is removed.
|
||||
*/
|
||||
static public function clean_row($row, $prefix = '')
|
||||
{
|
||||
// Upon creation of a user/group $row might be empty
|
||||
if (empty($row))
|
||||
{
|
||||
return self::$default_row;
|
||||
}
|
||||
|
||||
$output = array();
|
||||
foreach ($row as $key => $value)
|
||||
{
|
||||
$key = preg_replace("#^(?:{$prefix}_)#", '', $key);
|
||||
$output[$key] = $value;
|
||||
}
|
||||
|
||||
if ($prefix === 'group' && isset($output['id']))
|
||||
{
|
||||
$output['id'] = 'g' . $output['id'];
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean driver names that are returned from template files
|
||||
* Underscores are replaced with dots
|
||||
*
|
||||
* @param string $name Driver name
|
||||
*
|
||||
* @return string Cleaned driver name
|
||||
*/
|
||||
static public function clean_driver_name($name)
|
||||
{
|
||||
return str_replace(array('\\', '_'), '.', $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare driver names for use in template files
|
||||
* Dots are replaced with underscores
|
||||
*
|
||||
* @param string $name Clean driver name
|
||||
*
|
||||
* @return string Prepared driver name
|
||||
*/
|
||||
static public function prepare_driver_name($name)
|
||||
{
|
||||
return str_replace('.', '_', $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if avatar is enabled
|
||||
*
|
||||
* @param object $driver Avatar driver object
|
||||
*
|
||||
* @return bool True if avatar is enabled, false if it's disabled
|
||||
*/
|
||||
public function is_enabled($driver)
|
||||
{
|
||||
$config_name = $driver->get_config_name();
|
||||
|
||||
return $this->config["allow_avatar_{$config_name}"];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the settings array for enabling/disabling an avatar driver
|
||||
*
|
||||
* @param object $driver Avatar driver object
|
||||
*
|
||||
* @return array Array of configuration options as consumed by acp_board
|
||||
*/
|
||||
public function get_avatar_settings($driver)
|
||||
{
|
||||
$config_name = $driver->get_config_name();
|
||||
|
||||
return array(
|
||||
'allow_avatar_' . $config_name => array('lang' => 'ALLOW_' . strtoupper(str_replace('\\', '_', $config_name)), 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace "error" strings with their real, localized form
|
||||
*
|
||||
* @param \phpbb\user phpBB User object
|
||||
* @param array $error Array containing error strings
|
||||
* Key values can either be a string with a language key or an array
|
||||
* that will be passed to vsprintf() with the language key in the
|
||||
* first array key.
|
||||
*
|
||||
* @return array Array containing the localized error strings
|
||||
*/
|
||||
public function localize_errors(\phpbb\user $user, $error)
|
||||
{
|
||||
foreach ($error as $key => $lang)
|
||||
{
|
||||
if (is_array($lang))
|
||||
{
|
||||
$lang_key = array_shift($lang);
|
||||
$error[$key] = vsprintf($user->lang($lang_key), $lang);
|
||||
}
|
||||
else
|
||||
{
|
||||
$error[$key] = $user->lang("$lang");
|
||||
}
|
||||
}
|
||||
|
||||
return $error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle deleting avatars
|
||||
*
|
||||
* @param \phpbb\db\driver\driver_interface $db phpBB dbal
|
||||
* @param \phpbb\user $user phpBB user object
|
||||
* @param array $avatar_data Cleaned user data containing the user's
|
||||
* avatar data
|
||||
* @param string $table Database table from which the avatar should be deleted
|
||||
* @param string $prefix Prefix of user data columns in database
|
||||
* @return null
|
||||
*/
|
||||
public function handle_avatar_delete(\phpbb\db\driver\driver_interface $db, \phpbb\user $user, $avatar_data, $table, $prefix)
|
||||
{
|
||||
if ($driver = $this->get_driver($avatar_data['avatar_type']))
|
||||
{
|
||||
$driver->delete($avatar_data);
|
||||
}
|
||||
|
||||
$result = $this->prefix_avatar_columns($prefix, self::$default_row);
|
||||
|
||||
$sql = 'UPDATE ' . $table . '
|
||||
SET ' . $db->sql_build_array('UPDATE', $result) . '
|
||||
WHERE ' . $prefix . 'id = ' . (int) $avatar_data['id'];
|
||||
$db->sql_query($sql);
|
||||
|
||||
// Make sure we also delete this avatar from the users
|
||||
if ($prefix === 'group_')
|
||||
{
|
||||
$result = $this->prefix_avatar_columns('user_', self::$default_row);
|
||||
|
||||
$sql = 'UPDATE ' . USERS_TABLE . '
|
||||
SET ' . $db->sql_build_array('UPDATE', $result) . "
|
||||
WHERE user_avatar = '" . $db->sql_escape($avatar_data['avatar']) . "'";
|
||||
$db->sql_query($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Event is triggered after user avatar has been deleted
|
||||
*
|
||||
* @event core.avatar_manager_avatar_delete_after
|
||||
* @var \phpbb\user user phpBB user object
|
||||
* @var array avatar_data Normalised avatar-related user data
|
||||
* @var string table Table to delete avatar from
|
||||
* @var string prefix Column prefix to delete avatar from
|
||||
* @since 3.2.4-RC1
|
||||
*/
|
||||
$vars = array('user', 'avatar_data', 'table', 'prefix');
|
||||
extract($this->phpbb_dispatcher->trigger_event('core.avatar_manager_avatar_delete_after', compact($vars)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefix avatar columns
|
||||
*
|
||||
* @param string $prefix Column prefix
|
||||
* @param array $data Column data
|
||||
*
|
||||
* @return array Column data with prefixed column names
|
||||
*/
|
||||
public function prefix_avatar_columns($prefix, $data)
|
||||
{
|
||||
foreach ($data as $key => $value)
|
||||
{
|
||||
$data[$prefix . $key] = $value;
|
||||
unset($data[$key]);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
70
phpbb/cache/driver/apc.php
vendored
Normal file
70
phpbb/cache/driver/apc.php
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\cache\driver;
|
||||
|
||||
/**
|
||||
* ACM for APC
|
||||
*/
|
||||
class apc extends \phpbb\cache\driver\memory
|
||||
{
|
||||
var $extension = 'apc';
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function purge()
|
||||
{
|
||||
apc_clear_cache('user');
|
||||
|
||||
parent::purge();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch an item from the cache
|
||||
*
|
||||
* @access protected
|
||||
* @param string $var Cache key
|
||||
* @return mixed Cached data
|
||||
*/
|
||||
function _read($var)
|
||||
{
|
||||
return apc_fetch($this->key_prefix . $var);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store data in the cache
|
||||
*
|
||||
* @access protected
|
||||
* @param string $var Cache key
|
||||
* @param mixed $data Data to store
|
||||
* @param int $ttl Time-to-live of cached data
|
||||
* @return bool True if the operation succeeded
|
||||
*/
|
||||
function _write($var, $data, $ttl = 2592000)
|
||||
{
|
||||
return apc_store($this->key_prefix . $var, $data, $ttl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an item from the cache
|
||||
*
|
||||
* @access protected
|
||||
* @param string $var Cache key
|
||||
* @return bool True if the operation succeeded
|
||||
*/
|
||||
function _delete($var)
|
||||
{
|
||||
return apc_delete($this->key_prefix . $var);
|
||||
}
|
||||
}
|
||||
74
phpbb/cache/driver/apcu.php
vendored
Normal file
74
phpbb/cache/driver/apcu.php
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\cache\driver;
|
||||
|
||||
/**
|
||||
* ACM for APCU
|
||||
*/
|
||||
class apcu extends \phpbb\cache\driver\memory
|
||||
{
|
||||
var $extension = 'apcu';
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function purge()
|
||||
{
|
||||
/*
|
||||
* Use an iterator to selectively delete our cache entries without disturbing
|
||||
* any other cache users (e.g. other phpBB boards hosted on this server)
|
||||
*/
|
||||
apcu_delete(new \APCUIterator('#^' . $this->key_prefix . '#'));
|
||||
|
||||
parent::purge();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch an item from the cache
|
||||
*
|
||||
* @access protected
|
||||
* @param string $var Cache key
|
||||
* @return mixed Cached data
|
||||
*/
|
||||
function _read($var)
|
||||
{
|
||||
return apcu_fetch($this->key_prefix . $var);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store data in the cache
|
||||
*
|
||||
* @access protected
|
||||
* @param string $var Cache key
|
||||
* @param mixed $data Data to store
|
||||
* @param int $ttl Time-to-live of cached data
|
||||
* @return bool True if the operation succeeded
|
||||
*/
|
||||
function _write($var, $data, $ttl = 2592000)
|
||||
{
|
||||
return apcu_store($this->key_prefix . $var, $data, $ttl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an item from the cache
|
||||
*
|
||||
* @access protected
|
||||
* @param string $var Cache key
|
||||
* @return bool True if the operation succeeded
|
||||
*/
|
||||
function _delete($var)
|
||||
{
|
||||
return apcu_delete($this->key_prefix . $var);
|
||||
}
|
||||
}
|
||||
234
phpbb/cache/driver/base.php
vendored
Normal file
234
phpbb/cache/driver/base.php
vendored
Normal file
@@ -0,0 +1,234 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\cache\driver;
|
||||
|
||||
abstract class base implements \phpbb\cache\driver\driver_interface
|
||||
{
|
||||
var $vars = array();
|
||||
var $is_modified = false;
|
||||
|
||||
var $sql_rowset = array();
|
||||
var $sql_row_pointer = array();
|
||||
var $cache_dir = '';
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function purge()
|
||||
{
|
||||
// Purge all phpbb cache files
|
||||
try
|
||||
{
|
||||
$iterator = new \DirectoryIterator($this->cache_dir);
|
||||
}
|
||||
catch (\Exception $e)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($iterator as $fileInfo)
|
||||
{
|
||||
if ($fileInfo->isDot())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
$filename = $fileInfo->getFilename();
|
||||
if ($fileInfo->isDir())
|
||||
{
|
||||
$this->remove_dir($fileInfo->getPathname());
|
||||
}
|
||||
else if (strpos($filename, 'container_') === 0 ||
|
||||
strpos($filename, 'autoload_') === 0 ||
|
||||
strpos($filename, 'url_matcher') === 0 ||
|
||||
strpos($filename, 'url_generator') === 0 ||
|
||||
strpos($filename, 'sql_') === 0 ||
|
||||
strpos($filename, 'data_') === 0)
|
||||
{
|
||||
$this->remove_file($fileInfo->getPathname());
|
||||
}
|
||||
}
|
||||
|
||||
unset($this->vars);
|
||||
unset($this->sql_rowset);
|
||||
unset($this->sql_row_pointer);
|
||||
|
||||
if (function_exists('opcache_reset'))
|
||||
{
|
||||
@opcache_reset();
|
||||
}
|
||||
|
||||
$this->vars = array();
|
||||
$this->sql_rowset = array();
|
||||
$this->sql_row_pointer = array();
|
||||
|
||||
$this->is_modified = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function unload()
|
||||
{
|
||||
$this->save();
|
||||
unset($this->vars);
|
||||
unset($this->sql_rowset);
|
||||
unset($this->sql_row_pointer);
|
||||
|
||||
$this->vars = array();
|
||||
$this->sql_rowset = array();
|
||||
$this->sql_row_pointer = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_load($query)
|
||||
{
|
||||
// Remove extra spaces and tabs
|
||||
$query = preg_replace('/[\n\r\s\t]+/', ' ', $query);
|
||||
$query_id = md5($query);
|
||||
|
||||
if (($result = $this->_read('sql_' . $query_id)) === false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->sql_rowset[$query_id] = $result;
|
||||
$this->sql_row_pointer[$query_id] = 0;
|
||||
|
||||
return $query_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_exists($query_id)
|
||||
{
|
||||
return isset($this->sql_rowset[$query_id]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_fetchrow($query_id)
|
||||
{
|
||||
if ($this->sql_row_pointer[$query_id] < count($this->sql_rowset[$query_id]))
|
||||
{
|
||||
return $this->sql_rowset[$query_id][$this->sql_row_pointer[$query_id]++];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_fetchfield($query_id, $field)
|
||||
{
|
||||
if ($this->sql_row_pointer[$query_id] < count($this->sql_rowset[$query_id]))
|
||||
{
|
||||
return (isset($this->sql_rowset[$query_id][$this->sql_row_pointer[$query_id]][$field])) ? $this->sql_rowset[$query_id][$this->sql_row_pointer[$query_id]++][$field] : false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_rowseek($rownum, $query_id)
|
||||
{
|
||||
if ($rownum >= count($this->sql_rowset[$query_id]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->sql_row_pointer[$query_id] = $rownum;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_freeresult($query_id)
|
||||
{
|
||||
if (!isset($this->sql_rowset[$query_id]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
unset($this->sql_rowset[$query_id]);
|
||||
unset($this->sql_row_pointer[$query_id]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes/unlinks file
|
||||
*
|
||||
* @param string $filename Filename to remove
|
||||
* @param bool $check Check file permissions
|
||||
* @return bool True if the file was successfully removed, otherwise false
|
||||
*/
|
||||
function remove_file($filename, $check = false)
|
||||
{
|
||||
global $phpbb_filesystem;
|
||||
|
||||
if ($check && !$phpbb_filesystem->is_writable($this->cache_dir))
|
||||
{
|
||||
// E_USER_ERROR - not using language entry - intended.
|
||||
trigger_error('Unable to remove files within ' . $this->cache_dir . '. Please check directory permissions.', E_USER_ERROR);
|
||||
}
|
||||
|
||||
return @unlink($filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove directory
|
||||
*
|
||||
* @param string $dir Directory to remove
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
protected function remove_dir($dir)
|
||||
{
|
||||
try
|
||||
{
|
||||
$iterator = new \DirectoryIterator($dir);
|
||||
}
|
||||
catch (\Exception $e)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($iterator as $fileInfo)
|
||||
{
|
||||
if ($fileInfo->isDot())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($fileInfo->isDir())
|
||||
{
|
||||
$this->remove_dir($fileInfo->getPathname());
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->remove_file($fileInfo->getPathname());
|
||||
}
|
||||
}
|
||||
|
||||
@rmdir($dir);
|
||||
}
|
||||
}
|
||||
167
phpbb/cache/driver/driver_interface.php
vendored
Normal file
167
phpbb/cache/driver/driver_interface.php
vendored
Normal file
@@ -0,0 +1,167 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\cache\driver;
|
||||
|
||||
/**
|
||||
* An interface that all cache drivers must implement
|
||||
*/
|
||||
interface driver_interface
|
||||
{
|
||||
/**
|
||||
* Load global cache
|
||||
*
|
||||
* @return mixed False if an error was encountered, otherwise the data type of the cached data
|
||||
*/
|
||||
public function load();
|
||||
|
||||
/**
|
||||
* Unload cache object
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
public function unload();
|
||||
|
||||
/**
|
||||
* Save modified objects
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
public function save();
|
||||
|
||||
/**
|
||||
* Tidy cache
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
public function tidy();
|
||||
|
||||
/**
|
||||
* Get saved cache object
|
||||
*
|
||||
* @param string $var_name Cache key
|
||||
* @return mixed False if an error was encountered, otherwise the saved cached object
|
||||
*/
|
||||
public function get($var_name);
|
||||
|
||||
/**
|
||||
* Put data into cache
|
||||
*
|
||||
* @param string $var_name Cache key
|
||||
* @param mixed $var Cached data to store
|
||||
* @param int $ttl Time-to-live of cached data
|
||||
* @return null
|
||||
*/
|
||||
public function put($var_name, $var, $ttl = 0);
|
||||
|
||||
/**
|
||||
* Purge cache data
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
public function purge();
|
||||
|
||||
/**
|
||||
* Destroy cache data
|
||||
*
|
||||
* @param string $var_name Cache key
|
||||
* @param string $table Table name
|
||||
* @return null
|
||||
*/
|
||||
public function destroy($var_name, $table = '');
|
||||
|
||||
/**
|
||||
* Check if a given cache entry exists
|
||||
*
|
||||
* @param string $var_name Cache key
|
||||
*
|
||||
* @return bool True if cache file exists and has not expired.
|
||||
* False otherwise.
|
||||
*/
|
||||
public function _exists($var_name);
|
||||
|
||||
/**
|
||||
* Load result of an SQL query from cache.
|
||||
*
|
||||
* @param string $query SQL query
|
||||
*
|
||||
* @return int|bool Query ID (integer) if cache contains a rowset
|
||||
* for the specified query.
|
||||
* False otherwise.
|
||||
*/
|
||||
public function sql_load($query);
|
||||
|
||||
/**
|
||||
* Save result of an SQL query in cache.
|
||||
*
|
||||
* In persistent cache stores, this function stores the query
|
||||
* result to persistent storage. In other words, there is no need
|
||||
* to call save() afterwards.
|
||||
*
|
||||
* @param \phpbb\db\driver\driver_interface $db Database connection
|
||||
* @param string $query SQL query, should be used for generating storage key
|
||||
* @param mixed $query_result The result from \dbal::sql_query, to be passed to
|
||||
* \dbal::sql_fetchrow to get all rows and store them
|
||||
* in cache.
|
||||
* @param int $ttl Time to live, after this timeout the query should
|
||||
* expire from the cache.
|
||||
* @return int|mixed If storing in cache succeeded, an integer $query_id
|
||||
* representing the query should be returned. Otherwise
|
||||
* the original $query_result should be returned.
|
||||
*/
|
||||
public function sql_save(\phpbb\db\driver\driver_interface $db, $query, $query_result, $ttl);
|
||||
|
||||
/**
|
||||
* Check if result for a given SQL query exists in cache.
|
||||
*
|
||||
* @param int $query_id
|
||||
* @return bool
|
||||
*/
|
||||
public function sql_exists($query_id);
|
||||
|
||||
/**
|
||||
* Fetch row from cache (database)
|
||||
*
|
||||
* @param int $query_id
|
||||
* @return array|bool The query result if found in the cache, otherwise
|
||||
* false.
|
||||
*/
|
||||
public function sql_fetchrow($query_id);
|
||||
|
||||
/**
|
||||
* Fetch a field from the current row of a cached database result (database)
|
||||
*
|
||||
* @param int $query_id
|
||||
* @param string $field The name of the column.
|
||||
* @return string|bool The field of the query result if found in the cache,
|
||||
* otherwise false.
|
||||
*/
|
||||
public function sql_fetchfield($query_id, $field);
|
||||
|
||||
/**
|
||||
* Seek a specific row in an a cached database result (database)
|
||||
*
|
||||
* @param int $rownum Row to seek to.
|
||||
* @param int $query_id
|
||||
* @return bool
|
||||
*/
|
||||
public function sql_rowseek($rownum, $query_id);
|
||||
|
||||
/**
|
||||
* Free memory used for a cached database result (database)
|
||||
*
|
||||
* @param int $query_id
|
||||
* @return bool
|
||||
*/
|
||||
public function sql_freeresult($query_id);
|
||||
}
|
||||
153
phpbb/cache/driver/dummy.php
vendored
Normal file
153
phpbb/cache/driver/dummy.php
vendored
Normal file
@@ -0,0 +1,153 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\cache\driver;
|
||||
|
||||
/**
|
||||
* ACM dummy Caching
|
||||
*/
|
||||
class dummy extends \phpbb\cache\driver\base
|
||||
{
|
||||
/**
|
||||
* Set cache path
|
||||
*/
|
||||
function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function load()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function unload()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function save()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function tidy()
|
||||
{
|
||||
global $config;
|
||||
|
||||
// This cache always has a tidy room.
|
||||
$config->set('cache_last_gc', time(), false);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function get($var_name)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function put($var_name, $var, $ttl = 0)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function purge()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function destroy($var_name, $table = '')
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function _exists($var_name)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_load($query)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_save(\phpbb\db\driver\driver_interface $db, $query, $query_result, $ttl)
|
||||
{
|
||||
return $query_result;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_exists($query_id)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_fetchrow($query_id)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_fetchfield($query_id, $field)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_rowseek($rownum, $query_id)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_freeresult($query_id)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
107
phpbb/cache/driver/eaccelerator.php
vendored
Normal file
107
phpbb/cache/driver/eaccelerator.php
vendored
Normal file
@@ -0,0 +1,107 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\cache\driver;
|
||||
|
||||
/**
|
||||
* ACM for eAccelerator
|
||||
* @todo Missing locks from destroy() talk with David
|
||||
*/
|
||||
class eaccelerator extends \phpbb\cache\driver\memory
|
||||
{
|
||||
var $extension = 'eaccelerator';
|
||||
var $function = 'eaccelerator_get';
|
||||
|
||||
var $serialize_header = '#phpbb-serialized#';
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function purge()
|
||||
{
|
||||
foreach (eaccelerator_list_keys() as $var)
|
||||
{
|
||||
// @todo Check why the substr()
|
||||
// @todo Only unset vars matching $this->key_prefix
|
||||
eaccelerator_rm(substr($var['name'], 1));
|
||||
}
|
||||
|
||||
parent::purge();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function tidy()
|
||||
{
|
||||
global $config;
|
||||
|
||||
eaccelerator_gc();
|
||||
|
||||
$config->set('cache_last_gc', time(), false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch an item from the cache
|
||||
*
|
||||
* @access protected
|
||||
* @param string $var Cache key
|
||||
* @return mixed Cached data
|
||||
*/
|
||||
function _read($var)
|
||||
{
|
||||
$result = eaccelerator_get($this->key_prefix . $var);
|
||||
|
||||
if ($result === null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Handle serialized objects
|
||||
if (is_string($result) && strpos($result, $this->serialize_header . 'O:') === 0)
|
||||
{
|
||||
$result = unserialize(substr($result, strlen($this->serialize_header)));
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store data in the cache
|
||||
*
|
||||
* @access protected
|
||||
* @param string $var Cache key
|
||||
* @param mixed $data Data to store
|
||||
* @param int $ttl Time-to-live of cached data
|
||||
* @return bool True if the operation succeeded
|
||||
*/
|
||||
function _write($var, $data, $ttl = 2592000)
|
||||
{
|
||||
// Serialize objects and make them easy to detect
|
||||
$data = (is_object($data)) ? $this->serialize_header . serialize($data) : $data;
|
||||
|
||||
return eaccelerator_put($this->key_prefix . $var, $data, $ttl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an item from the cache
|
||||
*
|
||||
* @access protected
|
||||
* @param string $var Cache key
|
||||
* @return bool True if the operation succeeded
|
||||
*/
|
||||
function _delete($var)
|
||||
{
|
||||
return eaccelerator_rm($this->key_prefix . $var);
|
||||
}
|
||||
}
|
||||
613
phpbb/cache/driver/file.php
vendored
Normal file
613
phpbb/cache/driver/file.php
vendored
Normal file
@@ -0,0 +1,613 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\cache\driver;
|
||||
|
||||
/**
|
||||
* ACM File Based Caching
|
||||
*/
|
||||
class file extends \phpbb\cache\driver\base
|
||||
{
|
||||
var $var_expires = array();
|
||||
|
||||
/**
|
||||
* @var \phpbb\filesystem\filesystem_interface
|
||||
*/
|
||||
protected $filesystem;
|
||||
|
||||
/**
|
||||
* Set cache path
|
||||
*
|
||||
* @param string $cache_dir Define the path to the cache directory (default: $phpbb_root_path . 'cache/')
|
||||
*/
|
||||
function __construct($cache_dir = null)
|
||||
{
|
||||
global $phpbb_container;
|
||||
|
||||
$this->cache_dir = !is_null($cache_dir) ? $cache_dir : $phpbb_container->getParameter('core.cache_dir');
|
||||
$this->filesystem = new \phpbb\filesystem\filesystem();
|
||||
|
||||
if (!is_dir($this->cache_dir))
|
||||
{
|
||||
@mkdir($this->cache_dir, 0777, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function load()
|
||||
{
|
||||
return $this->_read('data_global');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function unload()
|
||||
{
|
||||
parent::unload();
|
||||
unset($this->var_expires);
|
||||
$this->var_expires = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function save()
|
||||
{
|
||||
if (!$this->is_modified)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
global $phpEx;
|
||||
|
||||
if (!$this->_write('data_global'))
|
||||
{
|
||||
// Now, this occurred how often? ... phew, just tell the user then...
|
||||
if (!$this->filesystem->is_writable($this->cache_dir))
|
||||
{
|
||||
// We need to use die() here, because else we may encounter an infinite loop (the message handler calls $cache->unload())
|
||||
die('Fatal: ' . $this->cache_dir . ' is NOT writable.');
|
||||
exit;
|
||||
}
|
||||
|
||||
die('Fatal: Not able to open ' . $this->cache_dir . 'data_global.' . $phpEx);
|
||||
exit;
|
||||
}
|
||||
|
||||
$this->is_modified = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function tidy()
|
||||
{
|
||||
global $config, $phpEx;
|
||||
|
||||
$dir = @opendir($this->cache_dir);
|
||||
|
||||
if (!$dir)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$time = time();
|
||||
|
||||
while (($entry = readdir($dir)) !== false)
|
||||
{
|
||||
if (!preg_match('/^(sql_|data_(?!global))/', $entry))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!($handle = @fopen($this->cache_dir . $entry, 'rb')))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip the PHP header
|
||||
fgets($handle);
|
||||
|
||||
// Skip expiration
|
||||
$expires = (int) fgets($handle);
|
||||
|
||||
fclose($handle);
|
||||
|
||||
if ($time >= $expires)
|
||||
{
|
||||
$this->remove_file($this->cache_dir . $entry);
|
||||
}
|
||||
}
|
||||
closedir($dir);
|
||||
|
||||
if (file_exists($this->cache_dir . 'data_global.' . $phpEx))
|
||||
{
|
||||
if (!count($this->vars))
|
||||
{
|
||||
$this->load();
|
||||
}
|
||||
|
||||
foreach ($this->var_expires as $var_name => $expires)
|
||||
{
|
||||
if ($time >= $expires)
|
||||
{
|
||||
$this->destroy($var_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$config->set('cache_last_gc', time(), false);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function get($var_name)
|
||||
{
|
||||
if ($var_name[0] == '_')
|
||||
{
|
||||
if (!$this->_exists($var_name))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->_read('data' . $var_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
return ($this->_exists($var_name)) ? $this->vars[$var_name] : false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function put($var_name, $var, $ttl = 31536000)
|
||||
{
|
||||
if ($var_name[0] == '_')
|
||||
{
|
||||
$this->_write('data' . $var_name, $var, time() + $ttl);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->vars[$var_name] = $var;
|
||||
$this->var_expires[$var_name] = time() + $ttl;
|
||||
$this->is_modified = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function purge()
|
||||
{
|
||||
parent::purge();
|
||||
$this->var_expires = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function destroy($var_name, $table = '')
|
||||
{
|
||||
global $phpEx;
|
||||
|
||||
if ($var_name == 'sql' && !empty($table))
|
||||
{
|
||||
if (!is_array($table))
|
||||
{
|
||||
$table = array($table);
|
||||
}
|
||||
|
||||
$dir = @opendir($this->cache_dir);
|
||||
|
||||
if (!$dir)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
while (($entry = readdir($dir)) !== false)
|
||||
{
|
||||
if (strpos($entry, 'sql_') !== 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!($handle = @fopen($this->cache_dir . $entry, 'rb')))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip the PHP header
|
||||
fgets($handle);
|
||||
|
||||
// Skip expiration
|
||||
fgets($handle);
|
||||
|
||||
// Grab the query, remove the LF
|
||||
$query = substr(fgets($handle), 0, -1);
|
||||
|
||||
fclose($handle);
|
||||
|
||||
foreach ($table as $check_table)
|
||||
{
|
||||
// Better catch partial table names than no table names. ;)
|
||||
if (strpos($query, $check_table) !== false)
|
||||
{
|
||||
$this->remove_file($this->cache_dir . $entry);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir($dir);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$this->_exists($var_name))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ($var_name[0] == '_')
|
||||
{
|
||||
$this->remove_file($this->cache_dir . 'data' . $var_name . ".$phpEx", true);
|
||||
}
|
||||
else if (isset($this->vars[$var_name]))
|
||||
{
|
||||
$this->is_modified = true;
|
||||
unset($this->vars[$var_name]);
|
||||
unset($this->var_expires[$var_name]);
|
||||
|
||||
// We save here to let the following cache hits succeed
|
||||
$this->save();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function _exists($var_name)
|
||||
{
|
||||
if ($var_name[0] == '_')
|
||||
{
|
||||
global $phpEx;
|
||||
$var_name = $this->clean_varname($var_name);
|
||||
return file_exists($this->cache_dir . 'data' . $var_name . ".$phpEx");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!count($this->vars))
|
||||
{
|
||||
$this->load();
|
||||
}
|
||||
|
||||
if (!isset($this->var_expires[$var_name]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return (time() > $this->var_expires[$var_name]) ? false : isset($this->vars[$var_name]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_save(\phpbb\db\driver\driver_interface $db, $query, $query_result, $ttl)
|
||||
{
|
||||
// Remove extra spaces and tabs
|
||||
$query = preg_replace('/[\n\r\s\t]+/', ' ', $query);
|
||||
|
||||
$query_id = md5($query);
|
||||
$this->sql_rowset[$query_id] = array();
|
||||
$this->sql_row_pointer[$query_id] = 0;
|
||||
|
||||
while ($row = $db->sql_fetchrow($query_result))
|
||||
{
|
||||
$this->sql_rowset[$query_id][] = $row;
|
||||
}
|
||||
$db->sql_freeresult($query_result);
|
||||
|
||||
if ($this->_write('sql_' . $query_id, $this->sql_rowset[$query_id], $ttl + time(), $query))
|
||||
{
|
||||
return $query_id;
|
||||
}
|
||||
|
||||
return $query_result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read cached data from a specified file
|
||||
*
|
||||
* @access private
|
||||
* @param string $filename Filename to write
|
||||
* @return mixed False if an error was encountered, otherwise the data type of the cached data
|
||||
*/
|
||||
function _read($filename)
|
||||
{
|
||||
global $phpEx;
|
||||
|
||||
$filename = $this->clean_varname($filename);
|
||||
$file = "{$this->cache_dir}$filename.$phpEx";
|
||||
|
||||
$type = substr($filename, 0, strpos($filename, '_'));
|
||||
|
||||
if (!file_exists($file))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!($handle = @fopen($file, 'rb')))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Skip the PHP header
|
||||
fgets($handle);
|
||||
|
||||
if ($filename == 'data_global')
|
||||
{
|
||||
$this->vars = $this->var_expires = array();
|
||||
|
||||
$time = time();
|
||||
|
||||
while (($expires = (int) fgets($handle)) && !feof($handle))
|
||||
{
|
||||
// Number of bytes of data
|
||||
$bytes = substr(fgets($handle), 0, -1);
|
||||
|
||||
if (!is_numeric($bytes) || ($bytes = (int) $bytes) === 0)
|
||||
{
|
||||
// We cannot process the file without a valid number of bytes
|
||||
// so we discard it
|
||||
fclose($handle);
|
||||
|
||||
$this->vars = $this->var_expires = array();
|
||||
$this->is_modified = false;
|
||||
|
||||
$this->remove_file($file);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($time >= $expires)
|
||||
{
|
||||
fseek($handle, $bytes, SEEK_CUR);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$var_name = substr(fgets($handle), 0, -1);
|
||||
|
||||
// Read the length of bytes that consists of data.
|
||||
$data = fread($handle, $bytes - strlen($var_name));
|
||||
$data = @unserialize($data);
|
||||
|
||||
// Don't use the data if it was invalid
|
||||
if ($data !== false)
|
||||
{
|
||||
$this->vars[$var_name] = $data;
|
||||
$this->var_expires[$var_name] = $expires;
|
||||
}
|
||||
|
||||
// Absorb the LF
|
||||
fgets($handle);
|
||||
}
|
||||
|
||||
fclose($handle);
|
||||
|
||||
$this->is_modified = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
$data = false;
|
||||
$line = 0;
|
||||
|
||||
while (($buffer = fgets($handle)) && !feof($handle))
|
||||
{
|
||||
$buffer = substr($buffer, 0, -1); // Remove the LF
|
||||
|
||||
// $buffer is only used to read integers
|
||||
// if it is non numeric we have an invalid
|
||||
// cache file, which we will now remove.
|
||||
if (!is_numeric($buffer))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if ($line == 0)
|
||||
{
|
||||
$expires = (int) $buffer;
|
||||
|
||||
if (time() >= $expires)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if ($type == 'sql')
|
||||
{
|
||||
// Skip the query
|
||||
fgets($handle);
|
||||
}
|
||||
}
|
||||
else if ($line == 1)
|
||||
{
|
||||
$bytes = (int) $buffer;
|
||||
|
||||
// Never should have 0 bytes
|
||||
if (!$bytes)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Grab the serialized data
|
||||
$data = fread($handle, $bytes);
|
||||
|
||||
// Read 1 byte, to trigger EOF
|
||||
fread($handle, 1);
|
||||
|
||||
if (!feof($handle))
|
||||
{
|
||||
// Somebody tampered with our data
|
||||
$data = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Something went wrong
|
||||
break;
|
||||
}
|
||||
$line++;
|
||||
}
|
||||
fclose($handle);
|
||||
|
||||
// unserialize if we got some data
|
||||
$data = ($data !== false) ? @unserialize($data) : $data;
|
||||
|
||||
if ($data === false)
|
||||
{
|
||||
$this->remove_file($file);
|
||||
return false;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write cache data to a specified file
|
||||
*
|
||||
* 'data_global' is a special case and the generated format is different for this file:
|
||||
* <code>
|
||||
* <?php exit; ?>
|
||||
* (expiration)
|
||||
* (length of var and serialised data)
|
||||
* (var)
|
||||
* (serialised data)
|
||||
* ... (repeat)
|
||||
* </code>
|
||||
*
|
||||
* The other files have a similar format:
|
||||
* <code>
|
||||
* <?php exit; ?>
|
||||
* (expiration)
|
||||
* (query) [SQL files only]
|
||||
* (length of serialised data)
|
||||
* (serialised data)
|
||||
* </code>
|
||||
*
|
||||
* @access private
|
||||
* @param string $filename Filename to write
|
||||
* @param mixed $data Data to store
|
||||
* @param int $expires Timestamp when the data expires
|
||||
* @param string $query Query when caching SQL queries
|
||||
* @return bool True if the file was successfully created, otherwise false
|
||||
*/
|
||||
function _write($filename, $data = null, $expires = 0, $query = '')
|
||||
{
|
||||
global $phpEx;
|
||||
|
||||
$filename = $this->clean_varname($filename);
|
||||
$file = "{$this->cache_dir}$filename.$phpEx";
|
||||
|
||||
$lock = new \phpbb\lock\flock($file);
|
||||
$lock->acquire();
|
||||
|
||||
if ($handle = @fopen($file, 'wb'))
|
||||
{
|
||||
// File header
|
||||
fwrite($handle, '<' . '?php exit; ?' . '>');
|
||||
|
||||
if ($filename == 'data_global')
|
||||
{
|
||||
// Global data is a different format
|
||||
foreach ($this->vars as $var => $data)
|
||||
{
|
||||
if (strpos($var, "\r") !== false || strpos($var, "\n") !== false)
|
||||
{
|
||||
// CR/LF would cause fgets() to read the cache file incorrectly
|
||||
// do not cache test entries, they probably won't be read back
|
||||
// the cache keys should really be alphanumeric with a few symbols.
|
||||
continue;
|
||||
}
|
||||
$data = serialize($data);
|
||||
|
||||
// Write out the expiration time
|
||||
fwrite($handle, "\n" . $this->var_expires[$var] . "\n");
|
||||
|
||||
// Length of the remaining data for this var (ignoring two LF's)
|
||||
fwrite($handle, strlen($data . $var) . "\n");
|
||||
fwrite($handle, $var . "\n");
|
||||
fwrite($handle, $data);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fwrite($handle, "\n" . $expires . "\n");
|
||||
|
||||
if (strpos($filename, 'sql_') === 0)
|
||||
{
|
||||
fwrite($handle, $query . "\n");
|
||||
}
|
||||
$data = serialize($data);
|
||||
|
||||
fwrite($handle, strlen($data) . "\n");
|
||||
fwrite($handle, $data);
|
||||
}
|
||||
|
||||
fclose($handle);
|
||||
|
||||
if (function_exists('opcache_invalidate'))
|
||||
{
|
||||
@opcache_invalidate($file);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$this->filesystem->phpbb_chmod($file, CHMOD_READ | CHMOD_WRITE);
|
||||
}
|
||||
catch (\phpbb\filesystem\exception\filesystem_exception $e)
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
$return_value = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
$return_value = false;
|
||||
}
|
||||
|
||||
$lock->release();
|
||||
|
||||
return $return_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace slashes in the file name
|
||||
*
|
||||
* @param string $varname name of a cache variable
|
||||
* @return string $varname name that is safe to use as a filename
|
||||
*/
|
||||
protected function clean_varname($varname)
|
||||
{
|
||||
return str_replace(array('/', '\\'), '-', $varname);
|
||||
}
|
||||
}
|
||||
122
phpbb/cache/driver/memcache.php
vendored
Normal file
122
phpbb/cache/driver/memcache.php
vendored
Normal file
@@ -0,0 +1,122 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\cache\driver;
|
||||
|
||||
if (!defined('PHPBB_ACM_MEMCACHE_PORT'))
|
||||
{
|
||||
define('PHPBB_ACM_MEMCACHE_PORT', 11211);
|
||||
}
|
||||
|
||||
if (!defined('PHPBB_ACM_MEMCACHE_COMPRESS'))
|
||||
{
|
||||
define('PHPBB_ACM_MEMCACHE_COMPRESS', false);
|
||||
}
|
||||
|
||||
if (!defined('PHPBB_ACM_MEMCACHE_HOST'))
|
||||
{
|
||||
define('PHPBB_ACM_MEMCACHE_HOST', 'localhost');
|
||||
}
|
||||
|
||||
if (!defined('PHPBB_ACM_MEMCACHE'))
|
||||
{
|
||||
//can define multiple servers with host1/port1,host2/port2 format
|
||||
define('PHPBB_ACM_MEMCACHE', PHPBB_ACM_MEMCACHE_HOST . '/' . PHPBB_ACM_MEMCACHE_PORT);
|
||||
}
|
||||
|
||||
/**
|
||||
* ACM for Memcached
|
||||
*/
|
||||
class memcache extends \phpbb\cache\driver\memory
|
||||
{
|
||||
var $extension = 'memcache';
|
||||
|
||||
var $memcache;
|
||||
var $flags = 0;
|
||||
|
||||
function __construct()
|
||||
{
|
||||
// Call the parent constructor
|
||||
parent::__construct();
|
||||
|
||||
$this->memcache = new \Memcache;
|
||||
foreach (explode(',', PHPBB_ACM_MEMCACHE) as $u)
|
||||
{
|
||||
preg_match('#(.*)/(\d+)#', $u, $parts);
|
||||
$this->memcache->addServer(trim($parts[1]), (int) trim($parts[2]));
|
||||
}
|
||||
$this->flags = (PHPBB_ACM_MEMCACHE_COMPRESS) ? MEMCACHE_COMPRESSED : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function unload()
|
||||
{
|
||||
parent::unload();
|
||||
|
||||
$this->memcache->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function purge()
|
||||
{
|
||||
$this->memcache->flush();
|
||||
|
||||
parent::purge();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch an item from the cache
|
||||
*
|
||||
* @access protected
|
||||
* @param string $var Cache key
|
||||
* @return mixed Cached data
|
||||
*/
|
||||
function _read($var)
|
||||
{
|
||||
return $this->memcache->get($this->key_prefix . $var);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store data in the cache
|
||||
*
|
||||
* @access protected
|
||||
* @param string $var Cache key
|
||||
* @param mixed $data Data to store
|
||||
* @param int $ttl Time-to-live of cached data
|
||||
* @return bool True if the operation succeeded
|
||||
*/
|
||||
function _write($var, $data, $ttl = 2592000)
|
||||
{
|
||||
if (!$this->memcache->replace($this->key_prefix . $var, $data, $this->flags, $ttl))
|
||||
{
|
||||
return $this->memcache->set($this->key_prefix . $var, $data, $this->flags, $ttl);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an item from the cache
|
||||
*
|
||||
* @access protected
|
||||
* @param string $var Cache key
|
||||
* @return bool True if the operation succeeded
|
||||
*/
|
||||
function _delete($var)
|
||||
{
|
||||
return $this->memcache->delete($this->key_prefix . $var);
|
||||
}
|
||||
}
|
||||
134
phpbb/cache/driver/memcached.php
vendored
Normal file
134
phpbb/cache/driver/memcached.php
vendored
Normal file
@@ -0,0 +1,134 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\cache\driver;
|
||||
|
||||
if (!defined('PHPBB_ACM_MEMCACHED_PORT'))
|
||||
{
|
||||
define('PHPBB_ACM_MEMCACHED_PORT', 11211);
|
||||
}
|
||||
|
||||
if (!defined('PHPBB_ACM_MEMCACHED_COMPRESS'))
|
||||
{
|
||||
define('PHPBB_ACM_MEMCACHED_COMPRESS', true);
|
||||
}
|
||||
|
||||
if (!defined('PHPBB_ACM_MEMCACHED_HOST'))
|
||||
{
|
||||
define('PHPBB_ACM_MEMCACHED_HOST', 'localhost');
|
||||
}
|
||||
|
||||
if (!defined('PHPBB_ACM_MEMCACHED'))
|
||||
{
|
||||
//can define multiple servers with host1/port1,host2/port2 format
|
||||
define('PHPBB_ACM_MEMCACHED', PHPBB_ACM_MEMCACHED_HOST . '/' . PHPBB_ACM_MEMCACHED_PORT);
|
||||
}
|
||||
|
||||
/**
|
||||
* ACM for Memcached
|
||||
*/
|
||||
class memcached extends \phpbb\cache\driver\memory
|
||||
{
|
||||
/** @var string Extension to use */
|
||||
protected $extension = 'memcached';
|
||||
|
||||
/** @var \Memcached Memcached class */
|
||||
protected $memcached;
|
||||
|
||||
/** @var int Flags */
|
||||
protected $flags = 0;
|
||||
|
||||
/**
|
||||
* Memcached constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
// Call the parent constructor
|
||||
parent::__construct();
|
||||
|
||||
$this->memcached = new \Memcached();
|
||||
$this->memcached->setOption(\Memcached::OPT_BINARY_PROTOCOL, true);
|
||||
// Memcached defaults to using compression, disable if we don't want
|
||||
// to use it
|
||||
if (!PHPBB_ACM_MEMCACHED_COMPRESS)
|
||||
{
|
||||
$this->memcached->setOption(\Memcached::OPT_COMPRESSION, false);
|
||||
}
|
||||
|
||||
foreach (explode(',', PHPBB_ACM_MEMCACHED) as $u)
|
||||
{
|
||||
preg_match('#(.*)/(\d+)#', $u, $parts);
|
||||
$this->memcached->addServer(trim($parts[1]), (int) trim($parts[2]));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function unload()
|
||||
{
|
||||
parent::unload();
|
||||
|
||||
unset($this->memcached);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function purge()
|
||||
{
|
||||
$this->memcached->flush();
|
||||
|
||||
parent::purge();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch an item from the cache
|
||||
*
|
||||
* @param string $var Cache key
|
||||
*
|
||||
* @return mixed Cached data
|
||||
*/
|
||||
protected function _read($var)
|
||||
{
|
||||
return $this->memcached->get($this->key_prefix . $var);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store data in the cache
|
||||
*
|
||||
* @param string $var Cache key
|
||||
* @param mixed $data Data to store
|
||||
* @param int $ttl Time-to-live of cached data
|
||||
* @return bool True if the operation succeeded
|
||||
*/
|
||||
protected function _write($var, $data, $ttl = 2592000)
|
||||
{
|
||||
if (!$this->memcached->replace($this->key_prefix . $var, $data, $ttl))
|
||||
{
|
||||
return $this->memcached->set($this->key_prefix . $var, $data, $ttl);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an item from the cache
|
||||
*
|
||||
* @param string $var Cache key
|
||||
* @return bool True if the operation succeeded
|
||||
*/
|
||||
protected function _delete($var)
|
||||
{
|
||||
return $this->memcached->delete($this->key_prefix . $var);
|
||||
}
|
||||
}
|
||||
282
phpbb/cache/driver/memory.php
vendored
Normal file
282
phpbb/cache/driver/memory.php
vendored
Normal file
@@ -0,0 +1,282 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\cache\driver;
|
||||
|
||||
/**
|
||||
* ACM Abstract Memory Class
|
||||
*/
|
||||
abstract class memory extends \phpbb\cache\driver\base
|
||||
{
|
||||
var $key_prefix;
|
||||
|
||||
/**
|
||||
* Set cache path
|
||||
*/
|
||||
function __construct()
|
||||
{
|
||||
global $phpbb_root_path, $dbname, $table_prefix, $phpbb_container;
|
||||
|
||||
$this->cache_dir = $phpbb_container->getParameter('core.cache_dir');
|
||||
$this->key_prefix = substr(md5($dbname . $table_prefix), 0, 8) . '_';
|
||||
|
||||
if (!isset($this->extension) || !extension_loaded($this->extension))
|
||||
{
|
||||
global $acm_type;
|
||||
|
||||
trigger_error("Could not find required extension [{$this->extension}] for the ACM module $acm_type.", E_USER_ERROR);
|
||||
}
|
||||
|
||||
if (isset($this->function) && !function_exists($this->function))
|
||||
{
|
||||
global $acm_type;
|
||||
|
||||
trigger_error("The required function [{$this->function}] is not available for the ACM module $acm_type.", E_USER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function load()
|
||||
{
|
||||
// grab the global cache
|
||||
$data = $this->_read('global');
|
||||
|
||||
if ($data !== false)
|
||||
{
|
||||
$this->vars = $data;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function save()
|
||||
{
|
||||
if (!$this->is_modified)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$this->_write('global', $this->vars, 2592000);
|
||||
|
||||
$this->is_modified = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function tidy()
|
||||
{
|
||||
global $config;
|
||||
|
||||
// cache has auto GC, no need to have any code here :)
|
||||
$config->set('cache_last_gc', time(), false);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function get($var_name)
|
||||
{
|
||||
if ($var_name[0] == '_')
|
||||
{
|
||||
if (!$this->_exists($var_name))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->_read($var_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
return ($this->_exists($var_name)) ? $this->vars[$var_name] : false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function put($var_name, $var, $ttl = 2592000)
|
||||
{
|
||||
if ($var_name[0] == '_')
|
||||
{
|
||||
$this->_write($var_name, $var, $ttl);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->vars[$var_name] = $var;
|
||||
$this->is_modified = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function destroy($var_name, $table = '')
|
||||
{
|
||||
if ($var_name == 'sql' && !empty($table))
|
||||
{
|
||||
if (!is_array($table))
|
||||
{
|
||||
$table = array($table);
|
||||
}
|
||||
|
||||
foreach ($table as $table_name)
|
||||
{
|
||||
// gives us the md5s that we want
|
||||
$temp = $this->_read('sql_' . $table_name);
|
||||
|
||||
if ($temp === false)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// delete each query ref
|
||||
foreach ($temp as $md5_id => $void)
|
||||
{
|
||||
$this->_delete('sql_' . $md5_id);
|
||||
}
|
||||
|
||||
// delete the table ref
|
||||
$this->_delete('sql_' . $table_name);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$this->_exists($var_name))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ($var_name[0] == '_')
|
||||
{
|
||||
$this->_delete($var_name);
|
||||
}
|
||||
else if (isset($this->vars[$var_name]))
|
||||
{
|
||||
$this->is_modified = true;
|
||||
unset($this->vars[$var_name]);
|
||||
|
||||
// We save here to let the following cache hits succeed
|
||||
$this->save();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function _exists($var_name)
|
||||
{
|
||||
if ($var_name[0] == '_')
|
||||
{
|
||||
return $this->_isset($var_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!count($this->vars))
|
||||
{
|
||||
$this->load();
|
||||
}
|
||||
|
||||
return isset($this->vars[$var_name]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function sql_save(\phpbb\db\driver\driver_interface $db, $query, $query_result, $ttl)
|
||||
{
|
||||
// Remove extra spaces and tabs
|
||||
$query = preg_replace('/[\n\r\s\t]+/', ' ', $query);
|
||||
$query_id = md5($query);
|
||||
|
||||
// determine which tables this query belongs to
|
||||
// Some queries use backticks, namely the get_database_size() query
|
||||
// don't check for conformity, the SQL would error and not reach here.
|
||||
if (!preg_match_all('/(?:FROM \\(?(`?\\w+`?(?: \\w+)?(?:, ?`?\\w+`?(?: \\w+)?)*)\\)?)|(?:JOIN (`?\\w+`?(?: \\w+)?))/', $query, $regs, PREG_SET_ORDER))
|
||||
{
|
||||
// Bail out if the match fails.
|
||||
return $query_result;
|
||||
}
|
||||
|
||||
$tables = array();
|
||||
foreach ($regs as $match)
|
||||
{
|
||||
if ($match[0][0] == 'F')
|
||||
{
|
||||
$tables = array_merge($tables, array_map('trim', explode(',', $match[1])));
|
||||
}
|
||||
else
|
||||
{
|
||||
$tables[] = $match[2];
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($tables as $table_name)
|
||||
{
|
||||
// Remove backticks
|
||||
$table_name = ($table_name[0] == '`') ? substr($table_name, 1, -1) : $table_name;
|
||||
|
||||
if (($pos = strpos($table_name, ' ')) !== false)
|
||||
{
|
||||
$table_name = substr($table_name, 0, $pos);
|
||||
}
|
||||
|
||||
$temp = $this->_read('sql_' . $table_name);
|
||||
|
||||
if ($temp === false)
|
||||
{
|
||||
$temp = array();
|
||||
}
|
||||
|
||||
$temp[$query_id] = true;
|
||||
|
||||
// This must never expire
|
||||
$this->_write('sql_' . $table_name, $temp, 0);
|
||||
}
|
||||
|
||||
// store them in the right place
|
||||
$this->sql_rowset[$query_id] = array();
|
||||
$this->sql_row_pointer[$query_id] = 0;
|
||||
|
||||
while ($row = $db->sql_fetchrow($query_result))
|
||||
{
|
||||
$this->sql_rowset[$query_id][] = $row;
|
||||
}
|
||||
$db->sql_freeresult($query_result);
|
||||
|
||||
$this->_write('sql_' . $query_id, $this->sql_rowset[$query_id], $ttl);
|
||||
|
||||
return $query_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a cache var exists
|
||||
*
|
||||
* @access protected
|
||||
* @param string $var Cache key
|
||||
* @return bool True if it exists, otherwise false
|
||||
*/
|
||||
function _isset($var)
|
||||
{
|
||||
// Most caches don't need to check
|
||||
return true;
|
||||
}
|
||||
}
|
||||
162
phpbb/cache/driver/redis.php
vendored
Normal file
162
phpbb/cache/driver/redis.php
vendored
Normal file
@@ -0,0 +1,162 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\cache\driver;
|
||||
|
||||
if (!defined('PHPBB_ACM_REDIS_PORT'))
|
||||
{
|
||||
define('PHPBB_ACM_REDIS_PORT', 6379);
|
||||
}
|
||||
|
||||
if (!defined('PHPBB_ACM_REDIS_HOST'))
|
||||
{
|
||||
define('PHPBB_ACM_REDIS_HOST', 'localhost');
|
||||
}
|
||||
|
||||
/**
|
||||
* ACM for Redis
|
||||
*
|
||||
* Compatible with the php extension phpredis available
|
||||
* at https://github.com/nicolasff/phpredis
|
||||
*
|
||||
*/
|
||||
class redis extends \phpbb\cache\driver\memory
|
||||
{
|
||||
var $extension = 'redis';
|
||||
|
||||
var $redis;
|
||||
|
||||
/**
|
||||
* Creates a redis cache driver.
|
||||
*
|
||||
* The following global constants affect operation:
|
||||
*
|
||||
* PHPBB_ACM_REDIS_HOST
|
||||
* PHPBB_ACM_REDIS_PORT
|
||||
* PHPBB_ACM_REDIS_PASSWORD
|
||||
* PHPBB_ACM_REDIS_DB
|
||||
*
|
||||
* There are no publicly documented constructor parameters.
|
||||
*/
|
||||
function __construct()
|
||||
{
|
||||
// Call the parent constructor
|
||||
parent::__construct();
|
||||
|
||||
$this->redis = new \Redis();
|
||||
|
||||
$args = func_get_args();
|
||||
if (!empty($args))
|
||||
{
|
||||
$ok = call_user_func_array(array($this->redis, 'connect'), $args);
|
||||
}
|
||||
else
|
||||
{
|
||||
$ok = $this->redis->connect(PHPBB_ACM_REDIS_HOST, PHPBB_ACM_REDIS_PORT);
|
||||
}
|
||||
|
||||
if (!$ok)
|
||||
{
|
||||
trigger_error('Could not connect to redis server');
|
||||
}
|
||||
|
||||
if (defined('PHPBB_ACM_REDIS_PASSWORD'))
|
||||
{
|
||||
if (!$this->redis->auth(PHPBB_ACM_REDIS_PASSWORD))
|
||||
{
|
||||
global $acm_type;
|
||||
|
||||
trigger_error("Incorrect password for the ACM module $acm_type.", E_USER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
$this->redis->setOption(\Redis::OPT_SERIALIZER, \Redis::SERIALIZER_PHP);
|
||||
$this->redis->setOption(\Redis::OPT_PREFIX, $this->key_prefix);
|
||||
|
||||
if (defined('PHPBB_ACM_REDIS_DB'))
|
||||
{
|
||||
if (!$this->redis->select(PHPBB_ACM_REDIS_DB))
|
||||
{
|
||||
global $acm_type;
|
||||
|
||||
trigger_error("Incorrect database for the ACM module $acm_type.", E_USER_ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function unload()
|
||||
{
|
||||
parent::unload();
|
||||
|
||||
$this->redis->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function purge()
|
||||
{
|
||||
$this->redis->flushDB();
|
||||
|
||||
parent::purge();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch an item from the cache
|
||||
*
|
||||
* @access protected
|
||||
* @param string $var Cache key
|
||||
* @return mixed Cached data
|
||||
*/
|
||||
function _read($var)
|
||||
{
|
||||
return $this->redis->get($var);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store data in the cache
|
||||
*
|
||||
* @access protected
|
||||
* @param string $var Cache key
|
||||
* @param mixed $data Data to store
|
||||
* @param int $ttl Time-to-live of cached data
|
||||
* @return bool True if the operation succeeded
|
||||
*/
|
||||
function _write($var, $data, $ttl = 2592000)
|
||||
{
|
||||
if ($ttl == 0)
|
||||
{
|
||||
return $this->redis->set($var, $data);
|
||||
}
|
||||
return $this->redis->setex($var, $ttl, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an item from the cache
|
||||
*
|
||||
* @access protected
|
||||
* @param string $var Cache key
|
||||
* @return bool True if the operation succeeded
|
||||
*/
|
||||
function _delete($var)
|
||||
{
|
||||
if ($this->redis->delete($var) > 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
73
phpbb/cache/driver/wincache.php
vendored
Normal file
73
phpbb/cache/driver/wincache.php
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\cache\driver;
|
||||
|
||||
/**
|
||||
* ACM for WinCache
|
||||
*/
|
||||
class wincache extends \phpbb\cache\driver\memory
|
||||
{
|
||||
var $extension = 'wincache';
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function purge()
|
||||
{
|
||||
wincache_ucache_clear();
|
||||
|
||||
parent::purge();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch an item from the cache
|
||||
*
|
||||
* @access protected
|
||||
* @param string $var Cache key
|
||||
* @return mixed Cached data
|
||||
*/
|
||||
function _read($var)
|
||||
{
|
||||
$success = false;
|
||||
$result = wincache_ucache_get($this->key_prefix . $var, $success);
|
||||
|
||||
return ($success) ? $result : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store data in the cache
|
||||
*
|
||||
* @access protected
|
||||
* @param string $var Cache key
|
||||
* @param mixed $data Data to store
|
||||
* @param int $ttl Time-to-live of cached data
|
||||
* @return bool True if the operation succeeded
|
||||
*/
|
||||
function _write($var, $data, $ttl = 2592000)
|
||||
{
|
||||
return wincache_ucache_set($this->key_prefix . $var, $data, $ttl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an item from the cache
|
||||
*
|
||||
* @access protected
|
||||
* @param string $var Cache key
|
||||
* @return bool True if the operation succeeded
|
||||
*/
|
||||
function _delete($var)
|
||||
{
|
||||
return wincache_ucache_delete($this->key_prefix . $var);
|
||||
}
|
||||
}
|
||||
107
phpbb/cache/driver/xcache.php
vendored
Normal file
107
phpbb/cache/driver/xcache.php
vendored
Normal file
@@ -0,0 +1,107 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\cache\driver;
|
||||
|
||||
/**
|
||||
* ACM for XCache
|
||||
*
|
||||
* To use this module you need ini_get() enabled and the following INI settings configured as follows:
|
||||
* - xcache.var_size > 0
|
||||
* - xcache.admin.enable_auth = off (or xcache.admin.user and xcache.admin.password set)
|
||||
*
|
||||
*/
|
||||
class xcache extends \phpbb\cache\driver\memory
|
||||
{
|
||||
var $extension = 'XCache';
|
||||
|
||||
function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
if (!function_exists('ini_get') || (int) ini_get('xcache.var_size') <= 0)
|
||||
{
|
||||
trigger_error('Increase xcache.var_size setting above 0 or enable ini_get() to use this ACM module.', E_USER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
function purge()
|
||||
{
|
||||
// Run before for XCache, if admin functions are disabled it will terminate execution
|
||||
parent::purge();
|
||||
|
||||
// If the admin authentication is enabled but not set up, this will cause a nasty error.
|
||||
// Not much we can do about it though.
|
||||
$n = xcache_count(XC_TYPE_VAR);
|
||||
|
||||
for ($i = 0; $i < $n; $i++)
|
||||
{
|
||||
xcache_clear_cache(XC_TYPE_VAR, $i);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch an item from the cache
|
||||
*
|
||||
* @access protected
|
||||
* @param string $var Cache key
|
||||
* @return mixed Cached data
|
||||
*/
|
||||
function _read($var)
|
||||
{
|
||||
$result = xcache_get($this->key_prefix . $var);
|
||||
|
||||
return ($result !== null) ? $result : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store data in the cache
|
||||
*
|
||||
* @access protected
|
||||
* @param string $var Cache key
|
||||
* @param mixed $data Data to store
|
||||
* @param int $ttl Time-to-live of cached data
|
||||
* @return bool True if the operation succeeded
|
||||
*/
|
||||
function _write($var, $data, $ttl = 2592000)
|
||||
{
|
||||
return xcache_set($this->key_prefix . $var, $data, $ttl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an item from the cache
|
||||
*
|
||||
* @access protected
|
||||
* @param string $var Cache key
|
||||
* @return bool True if the operation succeeded
|
||||
*/
|
||||
function _delete($var)
|
||||
{
|
||||
return xcache_unset($this->key_prefix . $var);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a cache var exists
|
||||
*
|
||||
* @access protected
|
||||
* @param string $var Cache key
|
||||
* @return bool True if it exists, otherwise false
|
||||
*/
|
||||
function _isset($var)
|
||||
{
|
||||
return xcache_isset($this->key_prefix . $var);
|
||||
}
|
||||
}
|
||||
390
phpbb/cache/service.php
vendored
Normal file
390
phpbb/cache/service.php
vendored
Normal file
@@ -0,0 +1,390 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\cache;
|
||||
|
||||
/**
|
||||
* Class for grabbing/handling cached entries
|
||||
*/
|
||||
class service
|
||||
{
|
||||
/**
|
||||
* Cache driver.
|
||||
*
|
||||
* @var \phpbb\cache\driver\driver_interface
|
||||
*/
|
||||
protected $driver;
|
||||
|
||||
/**
|
||||
* The config.
|
||||
*
|
||||
* @var \phpbb\config\config
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* Database connection.
|
||||
*
|
||||
* @var \phpbb\db\driver\driver_interface
|
||||
*/
|
||||
protected $db;
|
||||
|
||||
/**
|
||||
* Root path.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $phpbb_root_path;
|
||||
|
||||
/**
|
||||
* PHP file extension.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $php_ext;
|
||||
|
||||
/**
|
||||
* Creates a cache service around a cache driver
|
||||
*
|
||||
* @param \phpbb\cache\driver\driver_interface $driver The cache driver
|
||||
* @param \phpbb\config\config $config The config
|
||||
* @param \phpbb\db\driver\driver_interface $db Database connection
|
||||
* @param string $phpbb_root_path Root path
|
||||
* @param string $php_ext PHP file extension
|
||||
*/
|
||||
public function __construct(\phpbb\cache\driver\driver_interface $driver, \phpbb\config\config $config, \phpbb\db\driver\driver_interface $db, $phpbb_root_path, $php_ext)
|
||||
{
|
||||
$this->set_driver($driver);
|
||||
$this->config = $config;
|
||||
$this->db = $db;
|
||||
$this->phpbb_root_path = $phpbb_root_path;
|
||||
$this->php_ext = $php_ext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the cache driver used by this cache service.
|
||||
*
|
||||
* @return \phpbb\cache\driver\driver_interface The cache driver
|
||||
*/
|
||||
public function get_driver()
|
||||
{
|
||||
return $this->driver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the cache driver used by this cache service.
|
||||
*
|
||||
* @param \phpbb\cache\driver\driver_interface $driver The cache driver
|
||||
*/
|
||||
public function set_driver(\phpbb\cache\driver\driver_interface $driver)
|
||||
{
|
||||
$this->driver = $driver;
|
||||
}
|
||||
|
||||
public function __call($method, $arguments)
|
||||
{
|
||||
return call_user_func_array(array($this->driver, $method), $arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain list of naughty words and build preg style replacement arrays for use by the
|
||||
* calling script
|
||||
*/
|
||||
function obtain_word_list()
|
||||
{
|
||||
if (($censors = $this->driver->get('_word_censors')) === false)
|
||||
{
|
||||
$sql = 'SELECT word, replacement
|
||||
FROM ' . WORDS_TABLE;
|
||||
$result = $this->db->sql_query($sql);
|
||||
|
||||
$censors = array();
|
||||
while ($row = $this->db->sql_fetchrow($result))
|
||||
{
|
||||
$censors['match'][] = get_censor_preg_expression($row['word']);
|
||||
$censors['replace'][] = $row['replacement'];
|
||||
}
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
$this->driver->put('_word_censors', $censors);
|
||||
}
|
||||
|
||||
return $censors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain currently listed icons
|
||||
*/
|
||||
function obtain_icons()
|
||||
{
|
||||
if (($icons = $this->driver->get('_icons')) === false)
|
||||
{
|
||||
// Topic icons
|
||||
$sql = 'SELECT *
|
||||
FROM ' . ICONS_TABLE . '
|
||||
ORDER BY icons_order';
|
||||
$result = $this->db->sql_query($sql);
|
||||
|
||||
$icons = array();
|
||||
while ($row = $this->db->sql_fetchrow($result))
|
||||
{
|
||||
$icons[$row['icons_id']]['img'] = $row['icons_url'];
|
||||
$icons[$row['icons_id']]['width'] = (int) $row['icons_width'];
|
||||
$icons[$row['icons_id']]['height'] = (int) $row['icons_height'];
|
||||
$icons[$row['icons_id']]['alt'] = ($row['icons_alt']) ? $row['icons_alt'] : '';
|
||||
$icons[$row['icons_id']]['display'] = (bool) $row['display_on_posting'];
|
||||
}
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
$this->driver->put('_icons', $icons);
|
||||
}
|
||||
|
||||
return $icons;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain ranks
|
||||
*/
|
||||
function obtain_ranks()
|
||||
{
|
||||
if (($ranks = $this->driver->get('_ranks')) === false)
|
||||
{
|
||||
$sql = 'SELECT *
|
||||
FROM ' . RANKS_TABLE . '
|
||||
ORDER BY rank_min DESC';
|
||||
$result = $this->db->sql_query($sql);
|
||||
|
||||
$ranks = array();
|
||||
while ($row = $this->db->sql_fetchrow($result))
|
||||
{
|
||||
if ($row['rank_special'])
|
||||
{
|
||||
unset($row['rank_min']);
|
||||
$ranks['special'][$row['rank_id']] = $row;
|
||||
}
|
||||
else
|
||||
{
|
||||
$ranks['normal'][$row['rank_id']] = $row;
|
||||
}
|
||||
}
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
$this->driver->put('_ranks', $ranks);
|
||||
}
|
||||
|
||||
return $ranks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain allowed extensions
|
||||
*
|
||||
* @param mixed $forum_id If false then check for private messaging, if int then check for forum id. If true, then only return extension informations.
|
||||
*
|
||||
* @return array allowed extensions array.
|
||||
*/
|
||||
function obtain_attach_extensions($forum_id)
|
||||
{
|
||||
if (($extensions = $this->driver->get('_extensions')) === false)
|
||||
{
|
||||
$extensions = array(
|
||||
'_allowed_post' => array(),
|
||||
'_allowed_pm' => array(),
|
||||
);
|
||||
|
||||
// The rule is to only allow those extensions defined. ;)
|
||||
$sql = 'SELECT e.extension, g.*
|
||||
FROM ' . EXTENSIONS_TABLE . ' e, ' . EXTENSION_GROUPS_TABLE . ' g
|
||||
WHERE e.group_id = g.group_id
|
||||
AND (g.allow_group = 1 OR g.allow_in_pm = 1)';
|
||||
$result = $this->db->sql_query($sql);
|
||||
|
||||
while ($row = $this->db->sql_fetchrow($result))
|
||||
{
|
||||
$extension = strtolower(trim($row['extension']));
|
||||
|
||||
$extensions[$extension] = array(
|
||||
'display_cat' => (int) $row['cat_id'],
|
||||
'download_mode' => (int) $row['download_mode'],
|
||||
'upload_icon' => trim($row['upload_icon']),
|
||||
'max_filesize' => (int) $row['max_filesize'],
|
||||
'allow_group' => $row['allow_group'],
|
||||
'allow_in_pm' => $row['allow_in_pm'],
|
||||
'group_name' => $row['group_name'],
|
||||
);
|
||||
|
||||
$allowed_forums = ($row['allowed_forums']) ? unserialize(trim($row['allowed_forums'])) : array();
|
||||
|
||||
// Store allowed extensions forum wise
|
||||
if ($row['allow_group'])
|
||||
{
|
||||
$extensions['_allowed_post'][$extension] = (!count($allowed_forums)) ? 0 : $allowed_forums;
|
||||
}
|
||||
|
||||
if ($row['allow_in_pm'])
|
||||
{
|
||||
$extensions['_allowed_pm'][$extension] = 0;
|
||||
}
|
||||
}
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
$this->driver->put('_extensions', $extensions);
|
||||
}
|
||||
|
||||
// Forum post
|
||||
if ($forum_id === false)
|
||||
{
|
||||
// We are checking for private messages, therefore we only need to get the pm extensions...
|
||||
$return = array('_allowed_' => array());
|
||||
|
||||
foreach ($extensions['_allowed_pm'] as $extension => $check)
|
||||
{
|
||||
$return['_allowed_'][$extension] = 0;
|
||||
$return[$extension] = $extensions[$extension];
|
||||
}
|
||||
|
||||
$extensions = $return;
|
||||
}
|
||||
else if ($forum_id === true)
|
||||
{
|
||||
return $extensions;
|
||||
}
|
||||
else
|
||||
{
|
||||
$forum_id = (int) $forum_id;
|
||||
$return = array('_allowed_' => array());
|
||||
|
||||
foreach ($extensions['_allowed_post'] as $extension => $check)
|
||||
{
|
||||
// Check for allowed forums
|
||||
if (is_array($check))
|
||||
{
|
||||
$allowed = (!in_array($forum_id, $check)) ? false : true;
|
||||
}
|
||||
else
|
||||
{
|
||||
$allowed = true;
|
||||
}
|
||||
|
||||
if ($allowed)
|
||||
{
|
||||
$return['_allowed_'][$extension] = 0;
|
||||
$return[$extension] = $extensions[$extension];
|
||||
}
|
||||
}
|
||||
|
||||
$extensions = $return;
|
||||
}
|
||||
|
||||
if (!isset($extensions['_allowed_']))
|
||||
{
|
||||
$extensions['_allowed_'] = array();
|
||||
}
|
||||
|
||||
return $extensions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain active bots
|
||||
*/
|
||||
function obtain_bots()
|
||||
{
|
||||
if (($bots = $this->driver->get('_bots')) === false)
|
||||
{
|
||||
switch ($this->db->get_sql_layer())
|
||||
{
|
||||
case 'mssql_odbc':
|
||||
case 'mssqlnative':
|
||||
$sql = 'SELECT user_id, bot_agent, bot_ip
|
||||
FROM ' . BOTS_TABLE . '
|
||||
WHERE bot_active = 1
|
||||
ORDER BY LEN(bot_agent) DESC';
|
||||
break;
|
||||
|
||||
// LENGTH supported by MySQL, IBM DB2 and Oracle for sure...
|
||||
default:
|
||||
$sql = 'SELECT user_id, bot_agent, bot_ip
|
||||
FROM ' . BOTS_TABLE . '
|
||||
WHERE bot_active = 1
|
||||
ORDER BY LENGTH(bot_agent) DESC';
|
||||
break;
|
||||
}
|
||||
$result = $this->db->sql_query($sql);
|
||||
|
||||
$bots = array();
|
||||
while ($row = $this->db->sql_fetchrow($result))
|
||||
{
|
||||
$bots[] = $row;
|
||||
}
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
$this->driver->put('_bots', $bots);
|
||||
}
|
||||
|
||||
return $bots;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain cfg file data
|
||||
*/
|
||||
function obtain_cfg_items($style)
|
||||
{
|
||||
$parsed_array = $this->driver->get('_cfg_' . $style['style_path']);
|
||||
|
||||
if ($parsed_array === false)
|
||||
{
|
||||
$parsed_array = array();
|
||||
}
|
||||
|
||||
$filename = $this->phpbb_root_path . 'styles/' . $style['style_path'] . '/style.cfg';
|
||||
|
||||
if (!file_exists($filename))
|
||||
{
|
||||
return $parsed_array;
|
||||
}
|
||||
|
||||
if (!isset($parsed_array['filetime']) || (($this->config['load_tplcompile'] && @filemtime($filename) > $parsed_array['filetime'])))
|
||||
{
|
||||
// Re-parse cfg file
|
||||
$parsed_array = parse_cfg_file($filename);
|
||||
$parsed_array['filetime'] = @filemtime($filename);
|
||||
|
||||
$this->driver->put('_cfg_' . $style['style_path'], $parsed_array);
|
||||
}
|
||||
|
||||
return $parsed_array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain disallowed usernames
|
||||
*/
|
||||
function obtain_disallowed_usernames()
|
||||
{
|
||||
if (($usernames = $this->driver->get('_disallowed_usernames')) === false)
|
||||
{
|
||||
$sql = 'SELECT disallow_username
|
||||
FROM ' . DISALLOW_TABLE;
|
||||
$result = $this->db->sql_query($sql);
|
||||
|
||||
$usernames = array();
|
||||
while ($row = $this->db->sql_fetchrow($result))
|
||||
{
|
||||
$usernames[] = str_replace('%', '.*?', preg_quote(utf8_clean_string($row['disallow_username']), '#'));
|
||||
}
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
$this->driver->put('_disallowed_usernames', $usernames);
|
||||
}
|
||||
|
||||
return $usernames;
|
||||
}
|
||||
}
|
||||
277
phpbb/captcha/char_cube3d.php
Normal file
277
phpbb/captcha/char_cube3d.php
Normal file
@@ -0,0 +1,277 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\captcha;
|
||||
|
||||
class char_cube3d
|
||||
{
|
||||
var $bitmap;
|
||||
var $bitmap_width;
|
||||
var $bitmap_height;
|
||||
|
||||
var $basis_matrix = array(array(1, 0, 0), array(0, 1, 0), array(0, 0, 1));
|
||||
var $abs_x = array(1, 0);
|
||||
var $abs_y = array(0, 1);
|
||||
var $x = 0;
|
||||
var $y = 1;
|
||||
var $z = 2;
|
||||
var $letter = '';
|
||||
|
||||
/**
|
||||
*/
|
||||
function __construct(&$bitmaps, $letter)
|
||||
{
|
||||
$this->bitmap = $bitmaps['data'][$letter];
|
||||
$this->bitmap_width = $bitmaps['width'];
|
||||
$this->bitmap_height = $bitmaps['height'];
|
||||
|
||||
$this->basis_matrix[0][0] = mt_rand(-600, 600);
|
||||
$this->basis_matrix[0][1] = mt_rand(-600, 600);
|
||||
$this->basis_matrix[0][2] = (mt_rand(0, 1) * 2000) - 1000;
|
||||
$this->basis_matrix[1][0] = mt_rand(-1000, 1000);
|
||||
$this->basis_matrix[1][1] = mt_rand(-1000, 1000);
|
||||
$this->basis_matrix[1][2] = mt_rand(-1000, 1000);
|
||||
|
||||
$this->normalize($this->basis_matrix[0]);
|
||||
$this->normalize($this->basis_matrix[1]);
|
||||
$this->basis_matrix[2] = $this->cross_product($this->basis_matrix[0], $this->basis_matrix[1]);
|
||||
$this->normalize($this->basis_matrix[2]);
|
||||
|
||||
// $this->basis_matrix[1] might not be (probably isn't) orthogonal to $basis_matrix[0]
|
||||
$this->basis_matrix[1] = $this->cross_product($this->basis_matrix[0], $this->basis_matrix[2]);
|
||||
$this->normalize($this->basis_matrix[1]);
|
||||
|
||||
// Make sure our cube is facing into the canvas (assuming +z == in)
|
||||
for ($i = 0; $i < 3; ++$i)
|
||||
{
|
||||
if ($this->basis_matrix[$i][2] < 0)
|
||||
{
|
||||
$this->basis_matrix[$i][0] *= -1;
|
||||
$this->basis_matrix[$i][1] *= -1;
|
||||
$this->basis_matrix[$i][2] *= -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Force our "z" basis vector to be the one with greatest absolute z value
|
||||
$this->x = 0;
|
||||
$this->y = 1;
|
||||
$this->z = 2;
|
||||
|
||||
// Swap "y" with "z"
|
||||
if ($this->basis_matrix[1][2] > $this->basis_matrix[2][2])
|
||||
{
|
||||
$this->z = 1;
|
||||
$this->y = 2;
|
||||
}
|
||||
|
||||
// Swap "x" with "z"
|
||||
if ($this->basis_matrix[0][2] > $this->basis_matrix[$this->z][2])
|
||||
{
|
||||
$this->x = $this->z;
|
||||
$this->z = 0;
|
||||
}
|
||||
|
||||
// Still need to determine which of $x,$y are which.
|
||||
// wrong orientation if y's y-component is less than it's x-component
|
||||
// likewise if x's x-component is less than it's y-component
|
||||
// if they disagree, go with the one with the greater weight difference.
|
||||
// rotate if positive
|
||||
$weight = (abs($this->basis_matrix[$this->x][1]) - abs($this->basis_matrix[$this->x][0])) + (abs($this->basis_matrix[$this->y][0]) - abs($this->basis_matrix[$this->y][1]));
|
||||
|
||||
// Swap "x" with "y"
|
||||
if ($weight > 0)
|
||||
{
|
||||
list($this->x, $this->y) = array($this->y, $this->x);
|
||||
}
|
||||
|
||||
$this->abs_x = array($this->basis_matrix[$this->x][0], $this->basis_matrix[$this->x][1]);
|
||||
$this->abs_y = array($this->basis_matrix[$this->y][0], $this->basis_matrix[$this->y][1]);
|
||||
|
||||
if ($this->abs_x[0] < 0)
|
||||
{
|
||||
$this->abs_x[0] *= -1;
|
||||
$this->abs_x[1] *= -1;
|
||||
}
|
||||
|
||||
if ($this->abs_y[1] > 0)
|
||||
{
|
||||
$this->abs_y[0] *= -1;
|
||||
$this->abs_y[1] *= -1;
|
||||
}
|
||||
|
||||
$this->letter = $letter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw a character
|
||||
*/
|
||||
function drawchar($scale, $xoff, $yoff, $img, $background, $colours)
|
||||
{
|
||||
$width = $this->bitmap_width;
|
||||
$height = $this->bitmap_height;
|
||||
$bitmap = $this->bitmap;
|
||||
|
||||
$colour1 = $colours[array_rand($colours)];
|
||||
$colour2 = $colours[array_rand($colours)];
|
||||
|
||||
$swapx = ($this->basis_matrix[$this->x][0] > 0);
|
||||
$swapy = ($this->basis_matrix[$this->y][1] < 0);
|
||||
|
||||
for ($y = 0; $y < $height; ++$y)
|
||||
{
|
||||
for ($x = 0; $x < $width; ++$x)
|
||||
{
|
||||
$xp = ($swapx) ? ($width - $x - 1) : $x;
|
||||
$yp = ($swapy) ? ($height - $y - 1) : $y;
|
||||
|
||||
if ($bitmap[$height - $yp - 1][$xp])
|
||||
{
|
||||
$dx = $this->scale($this->abs_x, ($xp - ($swapx ? ($width / 2) : ($width / 2) - 1)) * $scale);
|
||||
$dy = $this->scale($this->abs_y, ($yp - ($swapy ? ($height / 2) : ($height / 2) - 1)) * $scale);
|
||||
$xo = $xoff + $dx[0] + $dy[0];
|
||||
$yo = $yoff + $dx[1] + $dy[1];
|
||||
|
||||
$origin = array(0, 0, 0);
|
||||
$xvec = $this->scale($this->basis_matrix[$this->x], $scale);
|
||||
$yvec = $this->scale($this->basis_matrix[$this->y], $scale);
|
||||
$face_corner = $this->sum2($xvec, $yvec);
|
||||
|
||||
$zvec = $this->scale($this->basis_matrix[$this->z], $scale);
|
||||
$x_corner = $this->sum2($xvec, $zvec);
|
||||
$y_corner = $this->sum2($yvec, $zvec);
|
||||
|
||||
imagefilledpolygon($img, $this->gen_poly($xo, $yo, $origin, $xvec, $x_corner,$zvec), 4, $colour1);
|
||||
imagefilledpolygon($img, $this->gen_poly($xo, $yo, $origin, $yvec, $y_corner,$zvec), 4, $colour2);
|
||||
|
||||
$face = $this->gen_poly($xo, $yo, $origin, $xvec, $face_corner, $yvec);
|
||||
|
||||
imagefilledpolygon($img, $face, 4, $background);
|
||||
imagepolygon($img, $face, 4, $colour1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* return a roughly acceptable range of sizes for rendering with this texttype
|
||||
*/
|
||||
function range()
|
||||
{
|
||||
return array(3, 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Vector length
|
||||
*/
|
||||
function vectorlen($vector)
|
||||
{
|
||||
return sqrt(pow($vector[0], 2) + pow($vector[1], 2) + pow($vector[2], 2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize
|
||||
*/
|
||||
function normalize(&$vector, $length = 1)
|
||||
{
|
||||
$length = (( $length < 1) ? 1 : $length);
|
||||
$length /= $this->vectorlen($vector);
|
||||
$vector[0] *= $length;
|
||||
$vector[1] *= $length;
|
||||
$vector[2] *= $length;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
function cross_product($vector1, $vector2)
|
||||
{
|
||||
$retval = array(0, 0, 0);
|
||||
$retval[0] = (($vector1[1] * $vector2[2]) - ($vector1[2] * $vector2[1]));
|
||||
$retval[1] = -(($vector1[0] * $vector2[2]) - ($vector1[2] * $vector2[0]));
|
||||
$retval[2] = (($vector1[0] * $vector2[1]) - ($vector1[1] * $vector2[0]));
|
||||
|
||||
return $retval;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
function sum($vector1, $vector2)
|
||||
{
|
||||
return array($vector1[0] + $vector2[0], $vector1[1] + $vector2[1], $vector1[2] + $vector2[2]);
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
function sum2($vector1, $vector2)
|
||||
{
|
||||
return array($vector1[0] + $vector2[0], $vector1[1] + $vector2[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
function scale($vector, $length)
|
||||
{
|
||||
if (count($vector) == 2)
|
||||
{
|
||||
return array($vector[0] * $length, $vector[1] * $length);
|
||||
}
|
||||
|
||||
return array($vector[0] * $length, $vector[1] * $length, $vector[2] * $length);
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
function gen_poly($xoff, $yoff, &$vec1, &$vec2, &$vec3, &$vec4)
|
||||
{
|
||||
$poly = array();
|
||||
$poly[0] = $xoff + $vec1[0];
|
||||
$poly[1] = $yoff + $vec1[1];
|
||||
$poly[2] = $xoff + $vec2[0];
|
||||
$poly[3] = $yoff + $vec2[1];
|
||||
$poly[4] = $xoff + $vec3[0];
|
||||
$poly[5] = $yoff + $vec3[1];
|
||||
$poly[6] = $xoff + $vec4[0];
|
||||
$poly[7] = $yoff + $vec4[1];
|
||||
|
||||
return $poly;
|
||||
}
|
||||
|
||||
/**
|
||||
* dimensions
|
||||
*/
|
||||
function dimensions($size)
|
||||
{
|
||||
$xn = $this->scale($this->basis_matrix[$this->x], -($this->bitmap_width / 2) * $size);
|
||||
$xp = $this->scale($this->basis_matrix[$this->x], ($this->bitmap_width / 2) * $size);
|
||||
$yn = $this->scale($this->basis_matrix[$this->y], -($this->bitmap_height / 2) * $size);
|
||||
$yp = $this->scale($this->basis_matrix[$this->y], ($this->bitmap_height / 2) * $size);
|
||||
|
||||
$p = array();
|
||||
$p[0] = $this->sum2($xn, $yn);
|
||||
$p[1] = $this->sum2($xp, $yn);
|
||||
$p[2] = $this->sum2($xp, $yp);
|
||||
$p[3] = $this->sum2($xn, $yp);
|
||||
|
||||
$min_x = $max_x = $p[0][0];
|
||||
$min_y = $max_y = $p[0][1];
|
||||
|
||||
for ($i = 1; $i < 4; ++$i)
|
||||
{
|
||||
$min_x = ($min_x > $p[$i][0]) ? $p[$i][0] : $min_x;
|
||||
$min_y = ($min_y > $p[$i][1]) ? $p[$i][1] : $min_y;
|
||||
$max_x = ($max_x < $p[$i][0]) ? $p[$i][0] : $max_x;
|
||||
$max_y = ($max_y < $p[$i][1]) ? $p[$i][1] : $max_y;
|
||||
}
|
||||
|
||||
return array($min_x, $min_y, $max_x, $max_y);
|
||||
}
|
||||
}
|
||||
527
phpbb/captcha/colour_manager.php
Normal file
527
phpbb/captcha/colour_manager.php
Normal file
@@ -0,0 +1,527 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\captcha;
|
||||
|
||||
class colour_manager
|
||||
{
|
||||
var $img;
|
||||
var $mode;
|
||||
var $colours;
|
||||
var $named_colours;
|
||||
|
||||
/**
|
||||
* Create the colour manager, link it to the image resource
|
||||
*/
|
||||
function __construct($img, $background = false, $mode = 'ahsv')
|
||||
{
|
||||
$this->img = $img;
|
||||
$this->mode = $mode;
|
||||
$this->colours = array();
|
||||
$this->named_colours = array();
|
||||
|
||||
if ($background !== false)
|
||||
{
|
||||
$bg = $this->allocate_named('background', $background);
|
||||
imagefill($this->img, 0, 0, $bg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup a named colour resource
|
||||
*/
|
||||
function get_resource($named_colour)
|
||||
{
|
||||
if (isset($this->named_colours[$named_colour]))
|
||||
{
|
||||
return $this->named_colours[$named_colour];
|
||||
}
|
||||
|
||||
if (isset($this->named_rgb[$named_colour]))
|
||||
{
|
||||
return $this->allocate_named($named_colour, $this->named_rgb[$named_colour], 'rgb');
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign a name to a colour resource
|
||||
*/
|
||||
function name_colour($name, $resource)
|
||||
{
|
||||
$this->named_colours[$name] = $resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* names and allocates a colour resource
|
||||
*/
|
||||
function allocate_named($name, $colour, $mode = false)
|
||||
{
|
||||
$resource = $this->allocate($colour, $mode);
|
||||
|
||||
if ($resource !== false)
|
||||
{
|
||||
$this->name_colour($name, $resource);
|
||||
}
|
||||
return $resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* allocates a specified colour into the image
|
||||
*/
|
||||
function allocate($colour, $mode = false)
|
||||
{
|
||||
if ($mode === false)
|
||||
{
|
||||
$mode = $this->mode;
|
||||
}
|
||||
|
||||
if (!is_array($colour))
|
||||
{
|
||||
if (isset($this->named_rgb[$colour]))
|
||||
{
|
||||
return $this->allocate_named($colour, $this->named_rgb[$colour], 'rgb');
|
||||
}
|
||||
|
||||
if (!is_int($colour))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$mode = 'rgb';
|
||||
$colour = array(255 & ($colour >> 16), 255 & ($colour >> 8), 255 & $colour);
|
||||
}
|
||||
|
||||
if (isset($colour['mode']))
|
||||
{
|
||||
$mode = $colour['mode'];
|
||||
unset($colour['mode']);
|
||||
}
|
||||
|
||||
if (isset($colour['random']))
|
||||
{
|
||||
unset($colour['random']);
|
||||
// everything else is params
|
||||
return $this->random_colour($colour, $mode);
|
||||
}
|
||||
|
||||
$rgb = $this->model_convert($colour, $mode, 'rgb');
|
||||
$store = ($this->mode == 'rgb') ? $rgb : $this->model_convert($colour, $mode, $this->mode);
|
||||
$resource = imagecolorallocate($this->img, $rgb[0], $rgb[1], $rgb[2]);
|
||||
$this->colours[$resource] = $store;
|
||||
|
||||
return $resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* randomly generates a colour, with optional params
|
||||
*/
|
||||
function random_colour($params = array(), $mode = false)
|
||||
{
|
||||
if ($mode === false)
|
||||
{
|
||||
$mode = $this->mode;
|
||||
}
|
||||
|
||||
switch ($mode)
|
||||
{
|
||||
case 'rgb':
|
||||
// @TODO random rgb generation. do we intend to do this, or is it just too tedious?
|
||||
break;
|
||||
|
||||
case 'ahsv':
|
||||
case 'hsv':
|
||||
default:
|
||||
|
||||
$default_params = array(
|
||||
'hue_bias' => false, // degree / 'r'/'g'/'b'/'c'/'m'/'y' /'o'
|
||||
'hue_range' => false, // if hue bias, then difference range +/- from bias
|
||||
'min_saturation' => 30, // 0 - 100
|
||||
'max_saturation' => 80, // 0 - 100
|
||||
'min_value' => 30, // 0 - 100
|
||||
'max_value' => 80, // 0 - 100
|
||||
);
|
||||
|
||||
$alt = ($mode == 'ahsv') ? true : false;
|
||||
$params = array_merge($default_params, $params);
|
||||
|
||||
$min_hue = 0;
|
||||
$max_hue = 359;
|
||||
$min_saturation = max(0, $params['min_saturation']);
|
||||
$max_saturation = min(100, $params['max_saturation']);
|
||||
$min_value = max(0, $params['min_value']);
|
||||
$max_value = min(100, $params['max_value']);
|
||||
|
||||
if ($params['hue_bias'] !== false)
|
||||
{
|
||||
if (is_numeric($params['hue_bias']))
|
||||
{
|
||||
$h = intval($params['hue_bias']) % 360;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch ($params['hue_bias'])
|
||||
{
|
||||
case 'o':
|
||||
$h = $alt ? 60 : 30;
|
||||
break;
|
||||
|
||||
case 'y':
|
||||
$h = $alt ? 120 : 60;
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
$h = $alt ? 180 : 120;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
$h = $alt ? 210 : 180;
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
$h = 240;
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
$h = 300;
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
default:
|
||||
$h = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$min_hue = $h + 360;
|
||||
$max_hue = $h + 360;
|
||||
|
||||
if ($params['hue_range'])
|
||||
{
|
||||
$min_hue -= min(180, $params['hue_range']);
|
||||
$max_hue += min(180, $params['hue_range']);
|
||||
}
|
||||
}
|
||||
|
||||
$h = mt_rand($min_hue, $max_hue);
|
||||
$s = mt_rand($min_saturation, $max_saturation);
|
||||
$v = mt_rand($min_value, $max_value);
|
||||
|
||||
return $this->allocate(array($h, $s, $v), $mode);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
function colour_scheme($resource, $include_original = true)
|
||||
{
|
||||
$mode = 'hsv';
|
||||
|
||||
if (($pre = $this->get_resource($resource)) !== false)
|
||||
{
|
||||
$resource = $pre;
|
||||
}
|
||||
|
||||
$colour = $this->model_convert($this->colours[$resource], $this->mode, $mode);
|
||||
$results = ($include_original) ? array($resource) : array();
|
||||
$colour2 = $colour3 = $colour4 = $colour;
|
||||
$colour2[0] += 150;
|
||||
$colour3[0] += 180;
|
||||
$colour4[0] += 210;
|
||||
|
||||
$results[] = $this->allocate($colour2, $mode);
|
||||
$results[] = $this->allocate($colour3, $mode);
|
||||
$results[] = $this->allocate($colour4, $mode);
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
function mono_range($resource, $count = 5, $include_original = true)
|
||||
{
|
||||
if (is_array($resource))
|
||||
{
|
||||
$results = array();
|
||||
for ($i = 0, $size = count($resource); $i < $size; ++$i)
|
||||
{
|
||||
$results = array_merge($results, $this->mono_range($resource[$i], $count, $include_original));
|
||||
}
|
||||
return $results;
|
||||
}
|
||||
|
||||
$mode = (in_array($this->mode, array('hsv', 'ahsv'), true) ? $this->mode : 'ahsv');
|
||||
if (($pre = $this->get_resource($resource)) !== false)
|
||||
{
|
||||
$resource = $pre;
|
||||
}
|
||||
|
||||
$colour = $this->model_convert($this->colours[$resource], $this->mode, $mode);
|
||||
|
||||
$results = array();
|
||||
if ($include_original)
|
||||
{
|
||||
$results[] = $resource;
|
||||
$count--;
|
||||
}
|
||||
|
||||
// This is a hard problem. I chicken out and try to maintain readability at the cost of less randomness.
|
||||
|
||||
while ($count > 0)
|
||||
{
|
||||
$colour[1] = ($colour[1] + mt_rand(40,60)) % 99;
|
||||
$colour[2] = ($colour[2] + mt_rand(40,60));
|
||||
$results[] = $this->allocate($colour, $mode);
|
||||
$count--;
|
||||
}
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert from one colour model to another
|
||||
*/
|
||||
function model_convert($colour, $from_model, $to_model)
|
||||
{
|
||||
if ($from_model == $to_model)
|
||||
{
|
||||
return $colour;
|
||||
}
|
||||
|
||||
switch ($to_model)
|
||||
{
|
||||
case 'hsv':
|
||||
|
||||
switch ($from_model)
|
||||
{
|
||||
case 'ahsv':
|
||||
return $this->ah2h($colour);
|
||||
break;
|
||||
|
||||
case 'rgb':
|
||||
return $this->rgb2hsv($colour);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'ahsv':
|
||||
|
||||
switch ($from_model)
|
||||
{
|
||||
case 'hsv':
|
||||
return $this->h2ah($colour);
|
||||
break;
|
||||
|
||||
case 'rgb':
|
||||
return $this->h2ah($this->rgb2hsv($colour));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'rgb':
|
||||
switch ($from_model)
|
||||
{
|
||||
case 'hsv':
|
||||
return $this->hsv2rgb($colour);
|
||||
break;
|
||||
|
||||
case 'ahsv':
|
||||
return $this->hsv2rgb($this->ah2h($colour));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Slightly altered from wikipedia's algorithm
|
||||
*/
|
||||
function hsv2rgb($hsv)
|
||||
{
|
||||
$this->normalize_hue($hsv[0]);
|
||||
|
||||
$h = $hsv[0];
|
||||
$s = min(1, max(0, $hsv[1] / 100));
|
||||
$v = min(1, max(0, $hsv[2] / 100));
|
||||
|
||||
// calculate hue sector
|
||||
$hi = floor($hsv[0] / 60);
|
||||
|
||||
// calculate opposite colour
|
||||
$p = $v * (1 - $s);
|
||||
|
||||
// calculate distance between hex vertices
|
||||
$f = ($h / 60) - $hi;
|
||||
|
||||
// coming in or going out?
|
||||
if (!($hi & 1))
|
||||
{
|
||||
$f = 1 - $f;
|
||||
}
|
||||
|
||||
// calculate adjacent colour
|
||||
$q = $v * (1 - ($f * $s));
|
||||
|
||||
switch ($hi)
|
||||
{
|
||||
case 0:
|
||||
$rgb = array($v, $q, $p);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
$rgb = array($q, $v, $p);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
$rgb = array($p, $v, $q);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
$rgb = array($p, $q, $v);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
$rgb = array($q, $p, $v);
|
||||
break;
|
||||
|
||||
case 5:
|
||||
$rgb = array($v, $p, $q);
|
||||
break;
|
||||
|
||||
default:
|
||||
return array(0, 0, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
return array(255 * $rgb[0], 255 * $rgb[1], 255 * $rgb[2]);
|
||||
}
|
||||
|
||||
/**
|
||||
* (more than) Slightly altered from wikipedia's algorithm
|
||||
*/
|
||||
function rgb2hsv($rgb)
|
||||
{
|
||||
$r = min(255, max(0, $rgb[0]));
|
||||
$g = min(255, max(0, $rgb[1]));
|
||||
$b = min(255, max(0, $rgb[2]));
|
||||
$max = max($r, $g, $b);
|
||||
$min = min($r, $g, $b);
|
||||
|
||||
$v = $max / 255;
|
||||
$s = (!$max) ? 0 : 1 - ($min / $max);
|
||||
|
||||
// if max - min is 0, we want hue to be 0 anyway.
|
||||
$h = $max - $min;
|
||||
|
||||
if ($h)
|
||||
{
|
||||
switch ($max)
|
||||
{
|
||||
case $g:
|
||||
$h = 120 + (60 * ($b - $r) / $h);
|
||||
break;
|
||||
|
||||
case $b:
|
||||
$h = 240 + (60 * ($r - $g) / $h);
|
||||
break;
|
||||
|
||||
case $r:
|
||||
$h = 360 + (60 * ($g - $b) / $h);
|
||||
break;
|
||||
}
|
||||
}
|
||||
$this->normalize_hue($h);
|
||||
|
||||
return array($h, $s * 100, $v * 100);
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
function normalize_hue(&$hue)
|
||||
{
|
||||
$hue %= 360;
|
||||
|
||||
if ($hue < 0)
|
||||
{
|
||||
$hue += 360;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Alternate hue to hue
|
||||
*/
|
||||
function ah2h($ahue)
|
||||
{
|
||||
if (is_array($ahue))
|
||||
{
|
||||
$ahue[0] = $this->ah2h($ahue[0]);
|
||||
return $ahue;
|
||||
}
|
||||
$this->normalize_hue($ahue);
|
||||
|
||||
// blue through red is already ok
|
||||
if ($ahue >= 240)
|
||||
{
|
||||
return $ahue;
|
||||
}
|
||||
|
||||
// ahue green is at 180
|
||||
if ($ahue >= 180)
|
||||
{
|
||||
// return (240 - (2 * (240 - $ahue)));
|
||||
return (2 * $ahue) - 240; // equivalent
|
||||
}
|
||||
|
||||
// ahue yellow is at 120 (RYB rather than RGB)
|
||||
if ($ahue >= 120)
|
||||
{
|
||||
return $ahue - 60;
|
||||
}
|
||||
|
||||
return $ahue / 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* hue to Alternate hue
|
||||
*/
|
||||
function h2ah($hue)
|
||||
{
|
||||
if (is_array($hue))
|
||||
{
|
||||
$hue[0] = $this->h2ah($hue[0]);
|
||||
return $hue;
|
||||
}
|
||||
$this->normalize_hue($hue);
|
||||
|
||||
// blue through red is already ok
|
||||
if ($hue >= 240)
|
||||
{
|
||||
return $hue;
|
||||
}
|
||||
else if ($hue <= 60)
|
||||
{
|
||||
return $hue * 2;
|
||||
}
|
||||
else if ($hue <= 120)
|
||||
{
|
||||
return $hue + 60;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ($hue + 240) / 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
88
phpbb/captcha/factory.php
Normal file
88
phpbb/captcha/factory.php
Normal file
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\captcha;
|
||||
|
||||
class factory
|
||||
{
|
||||
/**
|
||||
* @var \Symfony\Component\DependencyInjection\ContainerInterface
|
||||
*/
|
||||
private $container;
|
||||
|
||||
/**
|
||||
* @var \phpbb\di\service_collection
|
||||
*/
|
||||
private $plugins;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \Symfony\Component\DependencyInjection\ContainerInterface $container
|
||||
* @param \phpbb\di\service_collection $plugins
|
||||
*/
|
||||
public function __construct(\Symfony\Component\DependencyInjection\ContainerInterface $container, \phpbb\di\service_collection $plugins)
|
||||
{
|
||||
$this->container = $container;
|
||||
$this->plugins = $plugins;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new instance of a given plugin
|
||||
*
|
||||
* @param $name
|
||||
* @return object
|
||||
*/
|
||||
public function get_instance($name)
|
||||
{
|
||||
return $this->container->get($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the garbage collector
|
||||
*
|
||||
* @param string $name The name to the captcha service.
|
||||
*/
|
||||
function garbage_collect($name)
|
||||
{
|
||||
$captcha = $this->get_instance($name);
|
||||
$captcha->garbage_collect(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of all registered CAPTCHA plugins
|
||||
*
|
||||
* @returns array
|
||||
*/
|
||||
function get_captcha_types()
|
||||
{
|
||||
$captchas = array(
|
||||
'available' => array(),
|
||||
'unavailable' => array(),
|
||||
);
|
||||
|
||||
foreach ($this->plugins as $plugin => $plugin_instance)
|
||||
{
|
||||
if ($plugin_instance->is_available())
|
||||
{
|
||||
$captchas['available'][$plugin] = $plugin_instance->get_name();
|
||||
}
|
||||
else
|
||||
{
|
||||
$captchas['unavailable'][$plugin] = $plugin_instance->get_name();
|
||||
}
|
||||
}
|
||||
|
||||
return $captchas;
|
||||
}
|
||||
}
|
||||
1844
phpbb/captcha/gd.php
Normal file
1844
phpbb/captcha/gd.php
Normal file
File diff suppressed because it is too large
Load Diff
842
phpbb/captcha/gd_wave.php
Normal file
842
phpbb/captcha/gd_wave.php
Normal file
@@ -0,0 +1,842 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\captcha;
|
||||
|
||||
/**
|
||||
* Wave3D CAPTCHA
|
||||
*/
|
||||
class gd_wave
|
||||
{
|
||||
var $width = 360;
|
||||
var $height = 96;
|
||||
|
||||
function execute($code, $seed)
|
||||
{
|
||||
// seed the random generator
|
||||
mt_srand($seed);
|
||||
|
||||
// set height and width
|
||||
$img_x = $this->width;
|
||||
$img_y = $this->height;
|
||||
|
||||
// Generate image
|
||||
$img = imagecreatetruecolor($img_x, $img_y);
|
||||
$x_grid = mt_rand(6, 10);
|
||||
$y_grid = mt_rand(6, 10);
|
||||
|
||||
// Ok, so lets cut to the chase. We could accurately represent this in 3d and
|
||||
// do all the appropriate linear transforms. my questions is... why bother?
|
||||
// The computational overhead is unnecessary when you consider the simple fact:
|
||||
// we're not here to accurately represent a model, but to just show off some random-ish
|
||||
// polygons
|
||||
|
||||
// Conceive of 3 spaces.
|
||||
// 1) planar-space (discrete "pixel" grid)
|
||||
// 2) 3-space. (planar-space with z/height aspect)
|
||||
// 3) image space (pixels on the screen)
|
||||
// resolution of the planar-space we're embedding the text code in
|
||||
$plane_x = 100;
|
||||
$plane_y = 30;
|
||||
|
||||
$subdivision_factor = 3;
|
||||
|
||||
// $box is the 4 points in img_space that correspond to the corners of the plane in 3-space
|
||||
$box = array(
|
||||
'upper_left' => array(
|
||||
'x' => mt_rand(5, 15),
|
||||
'y' => mt_rand(10, 15)
|
||||
),
|
||||
'upper_right' => array(
|
||||
'x' => mt_rand($img_x - 35, $img_x - 19),
|
||||
'y' => mt_rand(10, 17)
|
||||
),
|
||||
'lower_left' => array(
|
||||
'x' => mt_rand($img_x - 45, $img_x - 5),
|
||||
'y' => mt_rand($img_y - 15, $img_y - 0),
|
||||
),
|
||||
);
|
||||
|
||||
$box['lower_right'] = array(
|
||||
'x' => $box['lower_left']['x'] + $box['upper_left']['x'] - $box['upper_right']['x'],
|
||||
'y' => $box['lower_left']['y'] + $box['upper_left']['y'] - $box['upper_right']['y'],
|
||||
);
|
||||
|
||||
// TODO
|
||||
$background = imagecolorallocate($img, mt_rand(155, 255), mt_rand(155, 255), mt_rand(155, 255));
|
||||
imagefill($img, 0, 0, $background);
|
||||
|
||||
$random = array();
|
||||
$fontcolors = array();
|
||||
|
||||
for ($i = 0; $i < 15; ++$i)
|
||||
{
|
||||
$random[$i] = imagecolorallocate($img, mt_rand(120, 255), mt_rand(120, 255), mt_rand(120, 255));
|
||||
}
|
||||
|
||||
$fontcolors[0] = imagecolorallocate($img, mt_rand(0, 120), mt_rand(0, 120), mt_rand(0, 120));
|
||||
|
||||
$colors = array();
|
||||
|
||||
$minr = mt_rand(20, 30);
|
||||
$ming = mt_rand(20, 30);
|
||||
$minb = mt_rand(20, 30);
|
||||
|
||||
$maxr = mt_rand(150, 230);
|
||||
$maxg = mt_rand(150, 230);
|
||||
$maxb = mt_rand(150, 230);
|
||||
|
||||
for ($i = -30; $i <= 30; ++$i)
|
||||
{
|
||||
$coeff1 = ($i + 12) / 45;
|
||||
$coeff2 = 1 - $coeff1;
|
||||
$colors[$i] = imagecolorallocate($img, ($coeff2 * $maxr) + ($coeff1 * $minr), ($coeff2 * $maxg) + ($coeff1 * $ming), ($coeff2 * $maxb) + ($coeff1 * $minb));
|
||||
}
|
||||
|
||||
// $img_buffer is the last row of 3-space positions (converted to img-space), cached
|
||||
// (using this means we don't need to recalculate all 4 positions for each new polygon,
|
||||
// merely the newest point that we're adding, which is then cached.
|
||||
$img_buffer = array(array(), array());
|
||||
|
||||
// In image-space, the x- and y-offset necessary to move one unit in the x-direction in planar-space
|
||||
$dxx = ($box['upper_right']['x'] - $box['upper_left']['x']) / ($subdivision_factor * $plane_x);
|
||||
$dxy = ($box['upper_right']['y'] - $box['upper_left']['y']) / ($subdivision_factor * $plane_x);
|
||||
|
||||
// In image-space, the x- and y-offset necessary to move one unit in the y-direction in planar-space
|
||||
$dyx = ($box['lower_right']['x'] - $box['upper_left']['x']) / ($subdivision_factor * $plane_y);
|
||||
$dyy = ($box['lower_right']['y'] - $box['upper_left']['y']) / ($subdivision_factor * $plane_y);
|
||||
|
||||
// Initial captcha-letter offset in planar-space
|
||||
$plane_offset_x = mt_rand(3, 8);
|
||||
$plane_offset_y = mt_rand( 12, 15);
|
||||
|
||||
// character map
|
||||
$map = $this->captcha_bitmaps();
|
||||
|
||||
// matrix
|
||||
$plane = array();
|
||||
|
||||
// for each character, we'll silkscreen it into our boolean pixel plane
|
||||
for ($c = 0, $code_num = strlen($code); $c < $code_num; ++$c)
|
||||
{
|
||||
$letter = $code[$c];
|
||||
|
||||
for ($x = $map['width'] - 1; $x >= 0; --$x)
|
||||
{
|
||||
for ($y = $map['height'] - 1; $y >= 0; --$y)
|
||||
{
|
||||
if ($map['data'][$letter][$y][$x])
|
||||
{
|
||||
$plane[$y + $plane_offset_y + (($c & 1) ? 1 : -1)][$x + $plane_offset_x] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
$plane_offset_x += 11;
|
||||
}
|
||||
|
||||
// calculate our first buffer, we can't actually draw polys with these yet
|
||||
// img_pos_prev == screen x,y location to our immediate left.
|
||||
// img_pos_cur == current screen x,y location
|
||||
// we calculate screen position of our
|
||||
// current cell based on the difference from the previous cell
|
||||
// rather than recalculating from absolute coordinates
|
||||
// What we cache into the $img_buffer contains the raised text coordinates.
|
||||
$img_pos_prev = $img_buffer[0][0] = array($box['upper_left']['x'], $box['upper_left']['y']);
|
||||
$prev_height = $this->wave_height(0, 0, $subdivision_factor);
|
||||
$full_x = $plane_x * $subdivision_factor;
|
||||
$full_y = $plane_y * $subdivision_factor;
|
||||
|
||||
for ($x = 1; $x <= $full_x; ++$x)
|
||||
{
|
||||
$cur_height = $this->wave_height($x, 0, $subdivision_factor);
|
||||
$offset = $cur_height - $prev_height;
|
||||
$img_pos_cur = array($img_pos_prev[0] + $dxx, $img_pos_prev[1] + $dxy + $offset);
|
||||
|
||||
$img_buffer[0][$x] = $img_pos_cur;
|
||||
$img_pos_prev = $img_pos_cur;
|
||||
$prev_height = $cur_height;
|
||||
}
|
||||
|
||||
for ($y = 1; $y <= $full_y; ++$y)
|
||||
{
|
||||
// swap buffers
|
||||
$buffer_cur = $y & 1;
|
||||
$buffer_prev = 1 - $buffer_cur;
|
||||
|
||||
$prev_height = $this->wave_height(0, $y, $subdivision_factor);
|
||||
$offset = $prev_height - $this->wave_height(0, $y - 1, $subdivision_factor);
|
||||
$img_pos_cur = array($img_buffer[$buffer_prev][0][0] + $dyx, min($img_buffer[$buffer_prev][0][1] + $dyy + $offset, $img_y - 1));
|
||||
|
||||
// make sure we don't try to write off the page
|
||||
$img_pos_prev = $img_pos_cur;
|
||||
|
||||
$img_buffer[$buffer_cur][0] = $img_pos_cur;
|
||||
|
||||
for ($x = 1; $x <= $full_x; ++$x)
|
||||
{
|
||||
$cur_height = $this->wave_height($x, $y, $subdivision_factor) + $this->grid_height($x, $y, $x_grid, $y_grid, 1);
|
||||
|
||||
// height is a z-factor, not a y-factor
|
||||
$offset = $cur_height - $prev_height;
|
||||
$img_pos_cur = array($img_pos_prev[0] + $dxx, $img_pos_prev[1] + $dxy + $offset);
|
||||
|
||||
// height is float, index it to an int, get closest color
|
||||
$color = $colors[intval($cur_height)];
|
||||
$img_pos_prev = $img_pos_cur;
|
||||
$prev_height = $cur_height;
|
||||
|
||||
$y_index_old = intval(($y - 1) / $subdivision_factor);
|
||||
$y_index_new = intval($y / $subdivision_factor);
|
||||
$x_index_old = intval(($x - 1) / $subdivision_factor);
|
||||
$x_index_new = intval($x / $subdivision_factor);
|
||||
|
||||
if (!empty($plane[$y_index_new][$x_index_new]))
|
||||
{
|
||||
$img_pos_cur[1] += $this->wave_height($x, $y, $subdivision_factor, 1) - 30 - $cur_height;
|
||||
$color = $colors[20];
|
||||
}
|
||||
$img_pos_cur[1] = min($img_pos_cur[1], $img_y - 1);
|
||||
$img_buffer[$buffer_cur][$x] = $img_pos_cur;
|
||||
|
||||
// Smooth the edges as much as possible by having not more than one low<->high traingle per square
|
||||
// Otherwise, just
|
||||
$diag_down = (empty($plane[$y_index_old][$x_index_old]) == empty($plane[$y_index_new][$x_index_new]));
|
||||
$diag_up = (empty($plane[$y_index_old][$x_index_new]) == empty($plane[$y_index_new][$x_index_old]));
|
||||
|
||||
// natural switching
|
||||
$mode = ($x + $y) & 1;
|
||||
|
||||
// override if it requires it
|
||||
if ($diag_down != $diag_up)
|
||||
{
|
||||
$mode = $diag_up;
|
||||
}
|
||||
|
||||
if ($mode)
|
||||
{
|
||||
// +-/ /
|
||||
// 1 |/ 2 /|
|
||||
// / /-+
|
||||
$poly1 = array_merge($img_buffer[$buffer_cur][$x - 1], $img_buffer[$buffer_prev][$x - 1], $img_buffer[$buffer_prev][$x]);
|
||||
$poly2 = array_merge($img_buffer[$buffer_cur][$x - 1], $img_buffer[$buffer_cur][$x], $img_buffer[$buffer_prev][$x]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// \ \-+
|
||||
// 1 |\ 2 \|
|
||||
// +-\ \
|
||||
$poly1 = array_merge($img_buffer[$buffer_cur][$x - 1], $img_buffer[$buffer_prev][$x - 1], $img_buffer[$buffer_cur][$x]);
|
||||
$poly2 = array_merge($img_buffer[$buffer_prev][$x - 1], $img_buffer[$buffer_prev][$x], $img_buffer[$buffer_cur][$x]);
|
||||
}
|
||||
|
||||
imagefilledpolygon($img, $poly1, 3, $color);
|
||||
imagefilledpolygon($img, $poly2, 3, $color);
|
||||
}
|
||||
}
|
||||
|
||||
// Output image
|
||||
header('Content-Type: image/png');
|
||||
header('Cache-control: no-cache, no-store');
|
||||
//$mtime = explode(' ', microtime());
|
||||
//$totaltime = $mtime[0] + $mtime[1] - $starttime;
|
||||
|
||||
//echo $totaltime . "<br />\n";
|
||||
//echo memory_get_usage() - $tmp;
|
||||
imagepng($img);
|
||||
imagedestroy($img);
|
||||
}
|
||||
|
||||
function wave_height($x, $y, $factor = 1, $tweak = 0.7)
|
||||
{
|
||||
// stretch the wave. TODO: pretty it up
|
||||
$x = $x/5 + 180;
|
||||
$y = $y/4;
|
||||
return ((sin($x / (3 * $factor)) + sin($y / (3 * $factor))) * 10 * $tweak);
|
||||
}
|
||||
|
||||
function grid_height($x, $y, $x_grid, $y_grid, $factor = 1)
|
||||
{
|
||||
return ((!($x % ($x_grid * $factor)) || !($y % ($y_grid * $factor))) ? 3 : 0);
|
||||
}
|
||||
|
||||
function captcha_bitmaps()
|
||||
{
|
||||
return array(
|
||||
'width' => 9,
|
||||
'height' => 13,
|
||||
'data' => array(
|
||||
'A' => array(
|
||||
array(0,0,1,1,1,1,0,0,0),
|
||||
array(0,1,0,0,0,0,1,0,0),
|
||||
array(1,0,0,0,0,0,0,1,0),
|
||||
array(1,0,0,0,0,0,0,1,0),
|
||||
array(1,0,0,0,0,0,0,1,0),
|
||||
array(1,0,0,0,0,0,0,1,0),
|
||||
array(1,0,0,0,0,0,0,1,0),
|
||||
array(1,1,1,1,1,1,1,1,0),
|
||||
array(1,0,0,0,0,0,0,1,0),
|
||||
array(1,0,0,0,0,0,0,1,0),
|
||||
array(1,0,0,0,0,0,0,1,0),
|
||||
array(1,0,0,0,0,0,0,1,0),
|
||||
array(1,0,0,0,0,0,0,1,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
),
|
||||
'B' => array(
|
||||
array(1,1,1,1,1,1,0,0,0),
|
||||
array(1,0,0,0,0,0,1,0,0),
|
||||
array(1,0,0,0,0,0,0,1,0),
|
||||
array(1,0,0,0,0,0,0,1,0),
|
||||
array(1,0,0,0,0,0,0,1,0),
|
||||
array(1,0,0,0,0,0,1,0,0),
|
||||
array(1,1,1,1,1,1,0,0,0),
|
||||
array(1,0,0,0,0,0,1,0,0),
|
||||
array(1,0,0,0,0,0,0,1,0),
|
||||
array(1,0,0,0,0,0,0,1,0),
|
||||
array(1,0,0,0,0,0,0,1,0),
|
||||
array(1,0,0,0,0,0,1,0,0),
|
||||
array(1,1,1,1,1,1,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
),
|
||||
'C' => array(
|
||||
array(0,0,1,1,1,1,1,0,0),
|
||||
array(0,1,0,0,0,0,0,1,0),
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(1,0,0,0,0,0,0,0,0),
|
||||
array(1,0,0,0,0,0,0,0,0),
|
||||
array(1,0,0,0,0,0,0,0,0),
|
||||
array(1,0,0,0,0,0,0,0,0),
|
||||
array(1,0,0,0,0,0,0,0,0),
|
||||
array(1,0,0,0,0,0,0,0,0),
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(0,1,0,0,0,0,0,1,0),
|
||||
array(0,0,1,1,1,1,1,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
),
|
||||
'D' => array(
|
||||
array(1,1,1,1,1,1,1,0,0),
|
||||
array(1,0,0,0,0,0,0,1,0),
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(1,0,0,0,0,0,0,1,0),
|
||||
array(1,1,1,1,1,1,1,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
),
|
||||
'E' => array(
|
||||
array(0,0,1,1,1,1,1,1,1),
|
||||
array(0,1,0,0,0,0,0,0,0),
|
||||
array(1,0,0,0,0,0,0,0,0),
|
||||
array(1,0,0,0,0,0,0,0,0),
|
||||
array(1,0,0,0,0,0,0,0,0),
|
||||
array(1,1,1,1,1,1,1,0,0),
|
||||
array(1,0,0,0,0,0,0,0,0),
|
||||
array(1,0,0,0,0,0,0,0,0),
|
||||
array(1,0,0,0,0,0,0,0,0),
|
||||
array(0,1,0,0,0,0,0,0,0),
|
||||
array(0,0,1,1,1,1,1,1,1),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
),
|
||||
'F' => array(
|
||||
array(0,0,1,1,1,1,1,1,0),
|
||||
array(0,1,0,0,0,0,0,0,0),
|
||||
array(1,0,0,0,0,0,0,0,0),
|
||||
array(1,0,0,0,0,0,0,0,0),
|
||||
array(1,0,0,0,0,0,0,0,0),
|
||||
array(1,1,1,1,1,1,0,0,0),
|
||||
array(1,0,0,0,0,0,0,0,0),
|
||||
array(1,0,0,0,0,0,0,0,0),
|
||||
array(1,0,0,0,0,0,0,0,0),
|
||||
array(1,0,0,0,0,0,0,0,0),
|
||||
array(1,0,0,0,0,0,0,0,0),
|
||||
array(1,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
),
|
||||
'G' => array(
|
||||
array(0,0,1,1,1,1,1,0,0),
|
||||
array(0,1,0,0,0,0,0,1,0),
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(1,0,0,0,0,0,0,0,0),
|
||||
array(1,0,0,0,0,0,0,0,0),
|
||||
array(1,0,0,0,0,0,0,0,0),
|
||||
array(1,0,0,0,0,0,0,1,1),
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(0,1,0,0,0,0,0,1,0),
|
||||
array(0,0,1,1,1,1,1,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
),
|
||||
'H' => array(
|
||||
array(1,0,0,0,0,0,1,0,0),
|
||||
array(1,0,0,0,0,0,1,0,0),
|
||||
array(1,0,0,0,0,0,1,0,0),
|
||||
array(1,0,0,0,0,0,1,0,0),
|
||||
array(1,0,0,0,0,0,1,0,0),
|
||||
array(1,1,1,1,1,1,1,0,0),
|
||||
array(1,0,0,0,0,0,1,0,0),
|
||||
array(1,0,0,0,0,0,1,0,0),
|
||||
array(1,0,0,0,0,0,1,0,0),
|
||||
array(1,0,0,0,0,0,1,0,0),
|
||||
array(1,0,0,0,0,0,1,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
),
|
||||
'I' => array(
|
||||
array(0,1,1,1,1,1,1,1,0),
|
||||
array(0,0,0,0,1,0,0,0,0),
|
||||
array(0,0,0,0,1,0,0,0,0),
|
||||
array(0,0,0,0,1,0,0,0,0),
|
||||
array(0,0,0,0,1,0,0,0,0),
|
||||
array(0,0,0,0,1,0,0,0,0),
|
||||
array(0,0,0,0,1,0,0,0,0),
|
||||
array(0,0,0,0,1,0,0,0,0),
|
||||
array(0,0,0,0,1,0,0,0,0),
|
||||
array(0,1,1,1,1,1,1,1,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
),
|
||||
'J' => array(
|
||||
array(0,0,0,0,0,0,1,1,1),
|
||||
array(0,0,0,0,0,0,0,0,1),
|
||||
array(0,0,0,0,0,0,0,0,1),
|
||||
array(0,0,0,0,0,0,0,0,1),
|
||||
array(0,0,0,0,0,0,0,0,1),
|
||||
array(0,0,0,0,0,0,0,0,1),
|
||||
array(0,0,0,0,0,0,0,0,1),
|
||||
array(0,1,0,0,0,0,0,0,1),
|
||||
array(0,1,0,0,0,0,0,0,1),
|
||||
array(0,0,1,0,0,0,0,1,0),
|
||||
array(0,0,0,1,1,1,1,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
),
|
||||
'K' => array(
|
||||
array(1,0,0,0,0,0,1,0,0),
|
||||
array(1,0,0,0,0,1,0,0,0),
|
||||
array(1,0,0,0,1,0,0,0,0),
|
||||
array(1,0,0,1,0,0,0,0,0),
|
||||
array(1,0,1,0,0,0,0,0,0),
|
||||
array(1,1,0,0,0,0,0,0,0),
|
||||
array(1,0,1,0,0,0,0,0,0),
|
||||
array(1,0,0,1,0,0,0,0,0),
|
||||
array(1,0,0,0,1,0,0,0,0),
|
||||
array(1,0,0,0,0,1,0,0,0),
|
||||
array(1,0,0,0,0,0,1,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
),
|
||||
'L' => array(
|
||||
array(1,0,0,0,0,0,0,0,0),
|
||||
array(1,0,0,0,0,0,0,0,0),
|
||||
array(1,0,0,0,0,0,0,0,0),
|
||||
array(1,0,0,0,0,0,0,0,0),
|
||||
array(1,0,0,0,0,0,0,0,0),
|
||||
array(1,0,0,0,0,0,0,0,0),
|
||||
array(1,0,0,0,0,0,0,0,0),
|
||||
array(1,0,0,0,0,0,0,0,0),
|
||||
array(1,0,0,0,0,0,0,0,0),
|
||||
array(0,1,0,0,0,0,0,0,0),
|
||||
array(0,0,1,1,1,1,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
),
|
||||
'M' => array(
|
||||
array(0,1,0,0,0,0,0,1,0),
|
||||
array(0,1,1,0,0,0,1,1,0),
|
||||
array(0,1,0,1,0,1,0,1,0),
|
||||
array(0,1,0,0,1,0,0,1,0),
|
||||
array(0,1,0,0,0,0,0,1,0),
|
||||
array(0,1,0,0,0,0,0,1,0),
|
||||
array(0,1,0,0,0,0,0,1,0),
|
||||
array(0,1,0,0,0,0,0,1,0),
|
||||
array(0,1,0,0,0,0,0,1,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
),
|
||||
'N' => array(
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(1,1,0,0,0,0,0,0,1),
|
||||
array(1,0,1,0,0,0,0,0,1),
|
||||
array(1,0,0,1,0,0,0,0,1),
|
||||
array(1,0,0,0,1,0,0,0,1),
|
||||
array(1,0,0,0,0,1,0,0,1),
|
||||
array(1,0,0,0,0,0,1,0,1),
|
||||
array(1,0,0,0,0,0,0,1,1),
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
),
|
||||
'O' => array(
|
||||
array(0,0,0,1,1,1,0,0,0),
|
||||
array(0,0,1,0,0,0,1,0,0),
|
||||
array(0,1,0,0,0,0,0,1,0),
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(0,1,0,0,0,0,0,1,0),
|
||||
array(0,0,1,0,0,0,1,0,0),
|
||||
array(0,0,0,1,1,1,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
),
|
||||
'P' => array(
|
||||
array(1,1,1,1,1,1,0,0,0),
|
||||
array(1,0,0,0,0,0,1,0,0),
|
||||
array(1,0,0,0,0,0,0,1,0),
|
||||
array(1,0,0,0,0,0,0,1,0),
|
||||
array(1,0,0,0,0,0,0,1,0),
|
||||
array(1,0,0,0,0,0,0,1,0),
|
||||
array(1,0,0,0,0,0,1,0,0),
|
||||
array(1,1,1,1,1,1,0,0,0),
|
||||
array(1,0,0,0,0,0,0,0,0),
|
||||
array(1,0,0,0,0,0,0,0,0),
|
||||
array(1,0,0,0,0,0,0,0,0),
|
||||
array(1,0,0,0,0,0,0,0,0),
|
||||
array(1,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
),
|
||||
'Q' => array(
|
||||
array(0,0,1,1,1,1,0,0,0),
|
||||
array(0,1,0,0,0,0,1,0,0),
|
||||
array(1,0,0,0,0,0,0,1,0),
|
||||
array(1,0,0,0,0,0,0,1,0),
|
||||
array(1,0,0,0,0,0,0,1,0),
|
||||
array(1,0,0,0,0,0,0,1,0),
|
||||
array(1,0,0,0,1,0,0,1,0),
|
||||
array(1,0,0,0,0,1,0,1,0),
|
||||
array(0,1,0,0,0,0,1,0,0),
|
||||
array(0,0,1,1,1,1,0,1,0),
|
||||
array(0,0,0,0,0,0,0,0,1),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
),
|
||||
'R' => array(
|
||||
array(1,1,1,1,1,1,0,0,0),
|
||||
array(1,0,0,0,0,0,1,0,0),
|
||||
array(1,0,0,0,0,0,0,1,0),
|
||||
array(1,0,0,0,0,0,0,1,0),
|
||||
array(1,0,0,0,0,0,0,1,0),
|
||||
array(1,0,0,0,0,0,1,0,0),
|
||||
array(1,1,1,1,1,1,0,0,0),
|
||||
array(1,0,1,0,0,0,0,0,0),
|
||||
array(1,0,0,1,0,0,0,0,0),
|
||||
array(1,0,0,0,1,0,0,0,0),
|
||||
array(1,0,0,0,0,1,0,0,0),
|
||||
array(1,0,0,0,0,0,1,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
),
|
||||
'S' => array(
|
||||
array(0,0,1,1,1,1,1,1,1),
|
||||
array(0,1,0,0,0,0,0,0,0),
|
||||
array(1,0,0,0,0,0,0,0,0),
|
||||
array(1,0,0,0,0,0,0,0,0),
|
||||
array(1,0,0,0,0,0,0,0,0),
|
||||
array(0,1,0,0,0,0,0,0,0),
|
||||
array(0,0,1,1,1,1,1,0,0),
|
||||
array(0,0,0,0,0,0,0,1,0),
|
||||
array(0,0,0,0,0,0,0,0,1),
|
||||
array(0,0,0,0,0,0,0,0,1),
|
||||
array(0,0,0,0,0,0,0,1,0),
|
||||
array(1,1,1,1,1,1,1,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
),
|
||||
'T' => array(
|
||||
array(1,1,1,1,1,1,1,1,1),
|
||||
array(0,0,0,0,1,0,0,0,0),
|
||||
array(0,0,0,0,1,0,0,0,0),
|
||||
array(0,0,0,0,1,0,0,0,0),
|
||||
array(0,0,0,0,1,0,0,0,0),
|
||||
array(0,0,0,0,1,0,0,0,0),
|
||||
array(0,0,0,0,1,0,0,0,0),
|
||||
array(0,0,0,0,1,0,0,0,0),
|
||||
array(0,0,0,0,1,0,0,0,0),
|
||||
array(0,0,0,0,1,0,0,0,0),
|
||||
array(0,0,0,0,1,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
),
|
||||
'U' => array(
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(0,1,0,0,0,0,0,1,0),
|
||||
array(0,0,1,1,1,1,1,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
),
|
||||
'V' => array(
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(0,1,0,0,0,0,0,1,0),
|
||||
array(0,0,1,0,0,0,1,0,0),
|
||||
array(0,0,0,1,0,1,0,0,0),
|
||||
array(0,0,0,0,1,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
),
|
||||
'W' => array(
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(1,0,0,0,1,0,0,0,1),
|
||||
array(1,0,0,1,0,1,0,0,1),
|
||||
array(1,0,1,0,0,0,1,0,1),
|
||||
array(1,1,0,0,0,0,0,1,1),
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
),
|
||||
'X' => array(
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(0,1,0,0,0,0,0,1,0),
|
||||
array(0,0,1,0,0,0,1,0,0),
|
||||
array(0,0,0,1,0,1,0,0,0),
|
||||
array(0,0,0,0,1,0,0,0,0),
|
||||
array(0,0,0,1,0,1,0,0,0),
|
||||
array(0,0,1,0,0,0,1,0,0),
|
||||
array(0,1,0,0,0,0,0,1,0),
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
),
|
||||
'Y' => array(
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(0,1,0,0,0,0,0,1,0),
|
||||
array(0,0,1,0,0,0,1,0,0),
|
||||
array(0,0,0,1,0,1,0,0,0),
|
||||
array(0,0,0,0,1,0,0,0,0),
|
||||
array(0,0,0,0,1,0,0,0,0),
|
||||
array(0,0,0,0,1,0,0,0,0),
|
||||
array(0,0,0,0,1,0,0,0,0),
|
||||
array(0,0,0,0,1,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
),
|
||||
'Z' => array(
|
||||
array(1,1,1,1,1,1,1,1,1),
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(0,0,0,0,0,0,0,1,0),
|
||||
array(0,0,0,0,0,0,1,0,0),
|
||||
array(0,0,0,0,0,1,0,0,0),
|
||||
array(0,0,0,0,1,0,0,0,0),
|
||||
array(0,0,0,1,0,0,0,0,0),
|
||||
array(0,0,1,0,0,0,0,0,0),
|
||||
array(0,1,0,0,0,0,0,0,0),
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(1,1,1,1,1,1,1,1,1),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
),
|
||||
'1' => array(
|
||||
array(0,0,0,0,1,0,0,0,0),
|
||||
array(0,0,0,1,1,0,0,0,0),
|
||||
array(0,0,1,0,1,0,0,0,0),
|
||||
array(0,1,0,0,1,0,0,0,0),
|
||||
array(0,0,0,0,1,0,0,0,0),
|
||||
array(0,0,0,0,1,0,0,0,0),
|
||||
array(0,0,0,0,1,0,0,0,0),
|
||||
array(0,0,0,0,1,0,0,0,0),
|
||||
array(0,0,0,0,1,0,0,0,0),
|
||||
array(0,0,0,0,1,0,0,0,0),
|
||||
array(0,0,0,0,1,0,0,0,0),
|
||||
array(0,1,1,1,1,1,1,1,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
),
|
||||
'2' => array(
|
||||
array(0,0,0,1,1,1,0,0,0),
|
||||
array(0,0,1,0,0,0,1,0,0),
|
||||
array(0,1,0,0,0,0,0,1,0),
|
||||
array(0,0,0,0,0,0,0,0,1),
|
||||
array(0,0,0,0,0,0,0,0,1),
|
||||
array(0,0,0,0,0,0,0,0,1),
|
||||
array(0,0,0,0,0,0,0,1,0),
|
||||
array(0,0,0,0,0,0,1,0,0),
|
||||
array(0,0,0,0,0,1,0,0,0),
|
||||
array(0,0,0,0,1,0,0,0,0),
|
||||
array(0,0,0,1,0,0,0,0,0),
|
||||
array(0,0,1,0,0,0,0,0,0),
|
||||
array(0,1,1,1,1,1,1,1,1),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
),
|
||||
'3' => array(
|
||||
array(0,0,0,1,1,1,1,0,0),
|
||||
array(0,0,1,0,0,0,0,1,0),
|
||||
array(0,1,0,0,0,0,0,0,1),
|
||||
array(0,0,0,0,0,0,0,0,1),
|
||||
array(0,0,0,0,0,0,0,0,1),
|
||||
array(0,0,0,0,0,0,0,1,0),
|
||||
array(0,0,0,0,0,1,1,0,0),
|
||||
array(0,0,0,0,0,0,0,1,0),
|
||||
array(0,0,0,0,0,0,0,0,1),
|
||||
array(0,0,0,0,0,0,0,0,1),
|
||||
array(0,1,0,0,0,0,0,0,1),
|
||||
array(0,0,1,0,0,0,0,1,0),
|
||||
array(0,0,0,1,1,1,1,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
),
|
||||
'4' => array(
|
||||
array(0,0,0,0,0,0,0,1,0),
|
||||
array(0,0,0,0,0,0,1,1,0),
|
||||
array(0,0,0,0,0,1,0,1,0),
|
||||
array(0,0,0,0,1,0,0,1,0),
|
||||
array(0,0,0,1,0,0,0,1,0),
|
||||
array(0,0,1,0,0,0,0,1,0),
|
||||
array(0,1,1,1,1,1,1,1,1),
|
||||
array(0,0,0,0,0,0,0,1,0),
|
||||
array(0,0,0,0,0,0,0,1,0),
|
||||
array(0,0,0,0,0,0,0,1,0),
|
||||
array(0,0,0,0,0,0,0,1,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
),
|
||||
'5' => array(
|
||||
array(1,1,1,1,1,1,1,1,1),
|
||||
array(1,0,0,0,0,0,0,0,0),
|
||||
array(1,0,0,0,0,0,0,0,0),
|
||||
array(1,0,0,0,0,0,0,0,0),
|
||||
array(0,1,0,0,0,0,0,0,0),
|
||||
array(0,0,1,1,1,1,1,0,0),
|
||||
array(0,0,0,0,0,0,0,1,0),
|
||||
array(0,0,0,0,0,0,0,0,1),
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(0,1,0,0,0,0,0,1,0),
|
||||
array(0,0,1,1,1,1,1,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
),
|
||||
'6' => array(
|
||||
array(0,0,1,1,1,1,1,0,0),
|
||||
array(0,1,0,0,0,0,0,1,0),
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(1,0,0,0,0,0,0,0,0),
|
||||
array(1,0,0,0,0,0,0,0,0),
|
||||
array(1,0,0,1,1,1,1,0,0),
|
||||
array(1,0,1,0,0,0,0,1,0),
|
||||
array(1,1,0,0,0,0,0,0,1),
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(0,1,0,0,0,0,0,1,0),
|
||||
array(0,0,1,1,1,1,1,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
),
|
||||
'7' => array(
|
||||
array(1,1,1,1,1,1,1,1,1),
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(0,0,0,0,0,0,0,1,0),
|
||||
array(0,0,0,0,0,0,1,0,0),
|
||||
array(0,0,0,0,0,1,0,0,0),
|
||||
array(0,0,0,0,1,0,0,0,0),
|
||||
array(0,0,0,0,1,0,0,0,0),
|
||||
array(0,0,0,0,1,0,0,0,0),
|
||||
array(0,0,0,0,1,0,0,0,0),
|
||||
array(0,0,0,0,1,0,0,0,0),
|
||||
array(0,0,0,0,1,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
),
|
||||
'8' => array(
|
||||
array(0,0,1,1,1,1,1,0,0),
|
||||
array(0,1,0,0,0,0,0,1,0),
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(0,1,0,0,0,0,0,1,0),
|
||||
array(0,0,1,1,1,1,1,0,0),
|
||||
array(0,1,0,0,0,0,0,1,0),
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(1,0,0,0,0,0,0,0,1),
|
||||
array(0,1,0,0,0,0,0,1,0),
|
||||
array(0,0,1,1,1,1,1,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
),
|
||||
'9' => array(
|
||||
array(0,0,0,1,1,1,1,0,0),
|
||||
array(0,0,1,0,0,0,0,1,0),
|
||||
array(0,1,0,0,0,0,0,0,1),
|
||||
array(0,1,0,0,0,0,0,0,1),
|
||||
array(0,1,0,0,0,0,0,0,1),
|
||||
array(0,1,0,0,0,0,0,1,1),
|
||||
array(0,0,1,1,1,1,1,0,1),
|
||||
array(0,0,0,0,0,0,0,0,1),
|
||||
array(0,0,0,0,0,0,0,0,1),
|
||||
array(0,1,0,0,0,0,0,0,1),
|
||||
array(0,0,1,0,0,0,0,1,0),
|
||||
array(0,0,0,1,1,1,1,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
array(0,0,0,0,0,0,0,0,0),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
386
phpbb/captcha/non_gd.php
Normal file
386
phpbb/captcha/non_gd.php
Normal file
@@ -0,0 +1,386 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\captcha;
|
||||
|
||||
/**
|
||||
* Main non-gd captcha class
|
||||
* @ignore
|
||||
*/
|
||||
class non_gd
|
||||
{
|
||||
var $filtered_pngs;
|
||||
var $width = 320;
|
||||
var $height = 50;
|
||||
|
||||
/**
|
||||
* Define filtered pngs on init
|
||||
*/
|
||||
function __construct()
|
||||
{
|
||||
// If we can we will generate a single filtered png, we avoid nastiness via emulation of some Zlib stuff
|
||||
$this->define_filtered_pngs();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the image containing $code with a seed of $seed
|
||||
*/
|
||||
function execute($code, $seed)
|
||||
{
|
||||
$img_height = $this->height - 10;
|
||||
$img_width = 0;
|
||||
|
||||
mt_srand($seed);
|
||||
|
||||
$char_widths = $hold_chars = array();
|
||||
$code_len = strlen($code);
|
||||
|
||||
for ($i = 0; $i < $code_len; $i++)
|
||||
{
|
||||
$char = $code[$i];
|
||||
|
||||
$width = mt_rand(0, 4);
|
||||
$raw_width = $this->filtered_pngs[$char]['width'];
|
||||
$char_widths[$i] = $width;
|
||||
$img_width += $raw_width - $width;
|
||||
|
||||
// Split the char into chunks of $raw_width + 1 length
|
||||
if (empty($hold_chars[$char]))
|
||||
{
|
||||
$hold_chars[$char] = str_split(base64_decode($this->filtered_pngs[$char]['data']), $raw_width + 1);
|
||||
}
|
||||
}
|
||||
|
||||
$offset_x = mt_rand(0, $this->width - $img_width);
|
||||
$offset_y = mt_rand(0, $this->height - $img_height);
|
||||
|
||||
$image = '';
|
||||
for ($i = 0; $i < $this->height; $i++)
|
||||
{
|
||||
$image .= chr(0);
|
||||
|
||||
if ($i > $offset_y && $i < $offset_y + $img_height)
|
||||
{
|
||||
for ($j = 0; $j < $offset_x; $j++)
|
||||
{
|
||||
$image .= chr(mt_rand(140, 255));
|
||||
}
|
||||
|
||||
for ($j = 0; $j < $code_len; $j++)
|
||||
{
|
||||
$image .= $this->randomise(substr($hold_chars[$code{$j}][$i - $offset_y - 1], 1), $char_widths[$j]);
|
||||
}
|
||||
|
||||
for ($j = $offset_x + $img_width; $j < $this->width; $j++)
|
||||
{
|
||||
$image .= chr(mt_rand(140, 255));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for ($j = 0; $j < $this->width; $j++)
|
||||
{
|
||||
$image .= chr(mt_rand(140, 255));
|
||||
}
|
||||
}
|
||||
}
|
||||
unset($hold_chars);
|
||||
|
||||
$image = $this->create_png($image, $this->width, $this->height);
|
||||
|
||||
// Output image
|
||||
header('Content-Type: image/png');
|
||||
header('Cache-control: no-cache, no-store');
|
||||
echo $image;
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is designed to randomise the pixels of the image data within
|
||||
* certain limits so as to keep it readable. It also varies the image
|
||||
* width a little
|
||||
*/
|
||||
function randomise($scanline, $width)
|
||||
{
|
||||
$new_line = '';
|
||||
|
||||
$end = strlen($scanline) - ceil($width/2);
|
||||
for ($i = (int) floor($width / 2); $i < $end; $i++)
|
||||
{
|
||||
$pixel = ord($scanline{$i});
|
||||
|
||||
if ($pixel < 190)
|
||||
{
|
||||
$new_line .= chr(mt_rand(0, 205));
|
||||
}
|
||||
else if ($pixel > 190)
|
||||
{
|
||||
$new_line .= chr(mt_rand(145, 255));
|
||||
}
|
||||
else
|
||||
{
|
||||
$new_line .= $scanline{$i};
|
||||
}
|
||||
}
|
||||
|
||||
return $new_line;
|
||||
}
|
||||
|
||||
/**
|
||||
* This creates a chunk of the given type, with the given data
|
||||
* of the given length adding the relevant crc
|
||||
*/
|
||||
function png_chunk($length, $type, $data)
|
||||
{
|
||||
$raw = $type . $data;
|
||||
|
||||
return pack('N', $length) . $raw . pack('N', crc32($raw));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates greyscale 8bit png - The PNG spec can be found at
|
||||
* http://www.libpng.org/pub/png/spec/PNG-Contents.html we use
|
||||
* png because it's a fully recognised open standard and supported
|
||||
* by practically all modern browsers and OSs
|
||||
*/
|
||||
function create_png($raw_image, $width, $height)
|
||||
{
|
||||
// SIG
|
||||
$image = pack('C8', 137, 80, 78, 71, 13, 10, 26, 10);
|
||||
|
||||
// IHDR
|
||||
$raw = pack('N2', $width, $height);
|
||||
$raw .= pack('C5', 8, 0, 0, 0, 0);
|
||||
$image .= $this->png_chunk(13, 'IHDR', $raw);
|
||||
|
||||
// IDAT
|
||||
if (@extension_loaded('zlib'))
|
||||
{
|
||||
$raw_image = gzcompress($raw_image);
|
||||
$length = strlen($raw_image);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The total length of this image, uncompressed, is just a calculation of pixels
|
||||
$length = ($width + 1) * $height;
|
||||
|
||||
// Adler-32 hash generation
|
||||
// Note: The hash is _backwards_ so we must reverse it
|
||||
|
||||
if (@extension_loaded('hash'))
|
||||
{
|
||||
$adler_hash = strrev(hash('adler32', $raw_image, true));
|
||||
}
|
||||
else if (@extension_loaded('mhash'))
|
||||
{
|
||||
$adler_hash = strrev(mhash(MHASH_ADLER32, $raw_image));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Optimized Adler-32 loop ported from the GNU Classpath project
|
||||
$temp_length = $length;
|
||||
$s1 = 1;
|
||||
$s2 = $index = 0;
|
||||
|
||||
while ($temp_length > 0)
|
||||
{
|
||||
// We can defer the modulo operation:
|
||||
// s1 maximally grows from 65521 to 65521 + 255 * 3800
|
||||
// s2 maximally grows by 3800 * median(s1) = 2090079800 < 2^31
|
||||
$substract_value = ($temp_length < 3800) ? $temp_length : 3800;
|
||||
$temp_length -= $substract_value;
|
||||
|
||||
while (--$substract_value >= 0)
|
||||
{
|
||||
$s1 += ord($raw_image[$index]);
|
||||
$s2 += $s1;
|
||||
|
||||
$index++;
|
||||
}
|
||||
|
||||
$s1 %= 65521;
|
||||
$s2 %= 65521;
|
||||
}
|
||||
$adler_hash = pack('N', ($s2 << 16) | $s1);
|
||||
}
|
||||
|
||||
// This is the same thing as gzcompress($raw_image, 0) but does not need zlib
|
||||
$raw_image = pack('C3v2', 0x78, 0x01, 0x01, $length, ~$length) . $raw_image . $adler_hash;
|
||||
|
||||
// The Zlib header + Adler hash make us add on 11
|
||||
$length += 11;
|
||||
}
|
||||
|
||||
// IDAT
|
||||
$image .= $this->png_chunk($length, 'IDAT', $raw_image);
|
||||
|
||||
// IEND
|
||||
$image .= $this->png_chunk(0, 'IEND', '');
|
||||
|
||||
return $image;
|
||||
}
|
||||
|
||||
/**
|
||||
* png image data
|
||||
* Each 'data' element is base64_encoded uncompressed IDAT
|
||||
*/
|
||||
function define_filtered_pngs()
|
||||
{
|
||||
$this->filtered_pngs = array(
|
||||
'0' => array(
|
||||
'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A///////////////////olFAkBAAAGDyA4P///M31/////////////wD////////////////0dAgAAAAAAAAAAAAEcPipFGHn////////////AP//////////////6DAAAAAAAAAAAAAAAAAALSEAN+T///////////8A//////////////xAAAAAAAAAAAAAAAAAAAAAACPA/////////////wD/////////////oAAAAAAAAAAAAAAAAAAAAAAAev//////////////AP////////////8oAAAAAAAAPNj/zDAAAAAAAABD//////////////8A////////////1AAAAAAAABjw////5BAAAAAAAADo/////////////wD///////////+QAAAAAAAAbP//////QgAAAAAAAKj/////////////AP///////////1wAAAAAAACs/////8AXAAAAAAAAcP////////////8A////////////OAAAAAAAAND////dNwAAAAAAAABI/////////////wD///////////8gAAAAAAAA4P//7koACwAAAAAAACT/////////////AP///////////wgAAAAAAAD///VqAwaPAAAAAAAAEP////////////8A////////////AAAAAAAAAP/8kQYDavUAAAAAAAAA/////////////wD///////////8AAAAAAAAA/6kNAEru/wAAAAAAAAD/////////////AP///////////wAAAAAAAADAIwA33f//AAAAAAAAAP////////////8A////////////FAAAAAAAADYAI8D///8AAAAAAAAQ/////////////wD///////////8kAAAAAAAAAA2p////5AAAAAAAACD/////////////AP///////////0gAAAAAAAAFkfz////UAAAAAAAAQP////////////8A////////////cAAAAAAAAET1/////7AAAAAAAABo/////////////wD///////////+oAAAAAAAAXfX/////sAAAAAAAAGj/////////////AAAAALgAAAAAAAAwAAAAAAAAAAAAAAD////////////oAAAAAAAACOT////oEAAAAAAAAOD/////////////AP////////////8+AAAAAAAAKMz/zDQAAAAAAAA0//////////////8A////////////7jgAAAAAAAAAAAAAAAAAAAAAAKT//////////////wD///////////VqAwIAAAAAAAAAAAAAAAAAAAA8////////////////AP//////////rQcDaVEAAAAAAAAAAAAAAAAAKOj///////////////8A///////////nblnu/IAIAAAAAAAAAAAAAFzw/////////////////wD////////////79////+iITCAAAAAgSITg////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////w==',
|
||||
'width' => 40
|
||||
),
|
||||
'1' => array(
|
||||
'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////8BAAAAAAAP//////////////////AP////////////////////////9sAAAAAAAA//////////////////8A////////////////////////pAAAAAAAAAD//////////////////wD//////////////////////6wEAAAAAAAAAP//////////////////AP////////////////////h4AAAAAAAAAAAA//////////////////8A//////////////////ygJAAAAAAAAAAAAAD//////////////////wD//////////////9x8HAAAAAAAAAAAAAAAAP//////////////////AP//////////////AAAAAAAAAAAAAAAAAAAA//////////////////8A//////////////8AAAAAAAAAAAAAAAAAAAD//////////////////wD//////////////wAAAAAAAAR4AAAAAAAAAP//////////////////AP//////////////AAAAAAA4zP8AAAAAAAAA//////////////////8A//////////////8AAAA4sP///wAAAAAAAAD//////////////////wD//////////////yR80P//////AAAAAAAAAP//////////////////AP////////////////////////8AAAAAAAAA//////////////////8A/////////////////////////wAAAAAAAAD//////////////////wD/////////////////////////AAAAAAAAAP//////////////////AP////////////////////////8AAAAAAAAA//////////////////8A/////////////////////////wAAAAAAAAD//////////////////wD/////////////////////////AAAAAAAAAP//////////////////AP////////////////////////8AAAAAAAAA//////////////////8A/////////////////////////wAAAAAAAAD//////////////////wD/////////////////////////AAAAAAAAAP//////////////////AP////////////////////////8AAAAAAAAA//////////////////8A/////////////////////////wAAAAAAAAD//////////////////wD/////////////////////////AAAAAAAAAP//////////////////AP////////////////////////8AAAAAAAAA//////////////////8A/////////////////////////wAAAAAAAAD//////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=',
|
||||
'width' => 40
|
||||
),
|
||||
'2' => array(
|
||||
'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP/////////////////okFAkCAAABCBIfNT///////////////////8A///////////////8hAgAAAAAAAAAAAAAAFTo/////////////////wD//////////////1QAAAAAAAAAAAAAAAAAACjo////////////////AP////////////+MAAAAAAAAAAAAAAAAAAAAADj///////////////8A////////////9BAAAAAAAAAAAAAAAAAAAAAAALD//////////////wD///////////+gAAAAAAAAAHjs+KwMAAAAAAAAVP//////////////AP///////////1gAAAAAAABM/////6QAAAAAAAAU//////////////8A////////////KAAAAAAAALj/////+AAAAAAAAAD//////////////wD///////////+MfGBMOCAI8P/////wAAAAAAAACP//////////////AP///////////////////////////5wAAAAAAAAw//////////////8A///////////////////////////oFAAAAAAAAHz//////////////wD/////////////////////////6CgAAAAAAAAE3P//////////////AP///////////////////////9ggAAAAAAAAAHT///////////////8A//////////////////////+0DAAAAAAAAAA8+P///////////////wD/////////////////////gAAAAAAAAAAAKOj/////////////////AP//////////////////9FAAAAAAAAAAADzw//////////////////8A/////////////////+g4AAAAAAAAAABk/P///////////////////wD////////////////oKAAAAAAAAAAMqP//////////////////////AP//////////////6CgAAAAAAAAAMNz///////////////////////8A//////////////g4AAAAAAAAAFT0/////////////////////////wD/////////////bAAAAAAAAABU/P//////////////////////////AP///////////8wAAAAAAAAAAAAAAAAAAAAAAAAA//////////////8A////////////SAAAAAAAAAAAAAAAAAAAAAAAAAD//////////////wD//////////9wAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////////AP//////////hAAAAAAAAAAAAAAAAAAAAAAAAAAA//////////////8A//////////9AAAAAAAAAAAAAAAAAAAAAAAAAAAD//////////////wD//////////xAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////////AP////////////////////////////////////////////////////8=',
|
||||
'width' => 40
|
||||
),
|
||||
'3' => array(
|
||||
'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD////////////////8sGg0FAAAACA4cLz8////////////////////AP//////////////rBgAAAAAAAAAAAAAACTA//////////////////8A/////////////3QAAAAAAAAAAAAAAAAAAASs/////////////////wD///////////+YAAAAAAAAAAAAAAAAAAAAAAjc////////////////AP//////////6AwAAAAAAAAAAAAAAAAAAAAAAGT///////////////8A//////////94AAAAAAAABJDw/8g4AAAAAAAAHP///////////////wD//////////yAAAAAAAACE/////9gAAAAAAAAA////////////////AP///////////NSwiGQ4FOT//////AAAAAAAABD///////////////8A//////////////////////////+YAAAAAAAAVP///////////////wD//////////////////////P/ggAQAAAAAAATM////////////////AP////////////////////9gAAAAAAAAAAAElP////////////////8A/////////////////////0AAAAAAAAAAHLj//////////////////wD/////////////////////OAAAAAAAAAAwkPj/////////////////AP////////////////////8gAAAAAAAAAAAAINj///////////////8A/////////////////////xAAAAAAAAAAAAAAIPD//////////////wD/////////////////////uOz/4HgEAAAAAAAAhP//////////////AP///////////////////////////3wAAAAAAAAw//////////////8A////////////////////////////6AAAAAAAAAj//////////////wD/////////////////////////////AAAAAAAAAP//////////////AP//////////tJh8YEQoDNz//////+AAAAAAAAAY//////////////8A//////////88AAAAAAAAaP//////dAAAAAAAAEz//////////////wD//////////6QAAAAAAAAAdOD/5HQAAAAAAAAApP//////////////AP///////////CgAAAAAAAAAAAAAAAAAAAAAACD4//////////////8A////////////yAQAAAAAAAAAAAAAAAAAAAAEuP///////////////wD/////////////rAQAAAAAAAAAAAAAAAAABJD/////////////////AP//////////////zDQAAAAAAAAAAAAAACTA//////////////////8A/////////////////8BwOCAAAAAUNGi0/P///////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=',
|
||||
'width' => 40
|
||||
),
|
||||
'4' => array(
|
||||
'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP//////////////////////////nAAAAAAAAAD///////////////8A/////////////////////////8AEAAAAAAAAAP///////////////wD////////////////////////gGAAAAAAAAAAA////////////////AP//////////////////////9DAAAAAAAAAAAAD///////////////8A//////////////////////9UAAAAAAAAAAAAAP///////////////wD/////////////////////hAAAAAAAAAAAAAAA////////////////AP///////////////////7QAAAAAAAAAAAAAAAD///////////////8A///////////////////UDAAAAAAUAAAAAAAAAP///////////////wD/////////////////7CQAAAAABMAAAAAAAAAA////////////////AP////////////////xEAAAAAACU/wAAAAAAAAD///////////////8A////////////////cAAAAAAAZP//AAAAAAAAAP///////////////wD//////////////6AAAAAAADz8//8AAAAAAAAA////////////////AP/////////////IBAAAAAAc6P///wAAAAAAAAD///////////////8A////////////5BgAAAAADMz/////AAAAAAAAAP///////////////wD///////////g0AAAAAACk//////8AAAAAAAAA////////////////AP//////////XAAAAAAAfP///////wAAAAAAAAD///////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////////8A////////////////////////////AAAAAAAAAP///////////////wD///////////////////////////8AAAAAAAAA////////////////AP///////////////////////////wAAAAAAAAD///////////////8A////////////////////////////AAAAAAAAAP///////////////wD///////////////////////////8AAAAAAAAA////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=',
|
||||
'width' => 40
|
||||
),
|
||||
'5' => array(
|
||||
'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP//////////////8AAAAAAAAAAAAAAAAAAAAAAA//////////////8A///////////////MAAAAAAAAAAAAAAAAAAAAAAD//////////////wD//////////////6wAAAAAAAAAAAAAAAAAAAAAAP//////////////AP//////////////iAAAAAAAAAAAAAAAAAAAAAAA//////////////8A//////////////9kAAAAAAAAAAAAAAAAAAAAAAD//////////////wD//////////////0QAAAAAAAAAAAAAAAAAAAAAAP//////////////AP//////////////IAAAAAAAYP////////////////////////////8A//////////////wAAAAAAAB8/////////////////////////////wD/////////////3AAAAAAAAIj/////////////////////////////AP////////////+4AAAAAAAAoLRYHAAEKGTE//////////////////8A/////////////5QAAAAAAAAQAAAAAAAAAABY9P///////////////wD/////////////dAAAAAAAAAAAAAAAAAAAAAA89P//////////////AP////////////9QAAAAAAAAAAAAAAAAAAAAAABg//////////////8A/////////////zAAAAAAAAAAAAAAAAAAAAAAAADQ/////////////wD/////////////IAAAAAAAAGjY/+h4BAAAAAAAAGz/////////////AP//////////////9NS0lHSc//////90AAAAAAAALP////////////8A/////////////////////////////9QAAAAAAAAE/////////////wD//////////////////////////////wAAAAAAAAD/////////////AP/////////////////////////////8AAAAAAAAEP////////////8A////////////pIRwWEAgDOD//////8wAAAAAAAA8/////////////wD///////////9EAAAAAAAAaP//////ZAAAAAAAAHz/////////////AP///////////6QAAAAAAAAAaOD/4GQAAAAAAAAE4P////////////8A/////////////CQAAAAAAAAAAAAAAAAAAAAAAGD//////////////wD/////////////yAQAAAAAAAAAAAAAAAAAAAAc7P//////////////AP//////////////rAwAAAAAAAAAAAAAAAAAGNj///////////////8A////////////////0EAAAAAAAAAAAAAAAFTo/////////////////wD//////////////////8h4QCAAAAAcQHzU////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=',
|
||||
'width' => 40
|
||||
),
|
||||
'6' => array(
|
||||
'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD///////////////////+0ZCwMAAAUNGjI////////////////////AP/////////////////EMAAAAAAAAAAAAABM6P////////////////8A////////////////lAQAAAAAAAAAAAAAAAAo6P///////////////wD//////////////6wAAAAAAAAAAAAAAAAAAABI////////////////AP/////////////oEAAAAAAAAAAAAAAAAAAAAACw//////////////8A/////////////3AAAAAAAAAoxP/YPAAAAAAAAEj//////////////wD////////////4EAAAAAAACOD////YDCBAVGiAoP//////////////AP///////////7gAAAAAAABY//////////////////////////////8A////////////eAAAAAAAAJT//////////////////////////////wD///////////9MAAAAAAAAvP/IXBgABCx03P//////////////////AP///////////ygAAAAAAADcdAAAAAAAAAAEiP////////////////8A////////////FAAAAAAAAFAAAAAAAAAAAAAAcP///////////////wD///////////8AAAAAAAAAAAAAAAAAAAAAAAAAlP//////////////AP///////////wAAAAAAAAAAAAAAAAAAAAAAAAAQ8P////////////8A////////////AAAAAAAAAABAyP/kZAAAAAAAAACQ/////////////wD///////////8MAAAAAAAALPj/////WAAAAAAAAET/////////////AP///////////yQAAAAAAACY///////MAAAAAAAAFP////////////8A////////////SAAAAAAAAMD///////wAAAAAAAAA/////////////wD///////////9wAAAAAAAAvP///////wAAAAAAAAD/////////////AP///////////7QAAAAAAACI///////UAAAAAAAAJP////////////8A////////////+AwAAAAAACDw/////2wAAAAAAABY/////////////wD/////////////cAAAAAAAADC8/Ox4AAAAAAAAAKj/////////////AP/////////////oEAAAAAAAAAAAAAAAAAAAAAAk/P////////////8A//////////////+oAAAAAAAAAAAAAAAAAAAABLj//////////////wD///////////////+QAAAAAAAAAAAAAAAAAACQ////////////////AP////////////////+0JAAAAAAAAAAAAAAkuP////////////////8A///////////////////8sGg0FAAADCxgqPz//////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=',
|
||||
'width' => 40
|
||||
),
|
||||
'7' => array(
|
||||
'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD///////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP///////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A////////////AAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD///////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP///////////wAAAAAAAAAAAAAAAAAAAAAAAAAABP////////////8A////////////AAAAAAAAAAAAAAAAAAAAAAAAAAy4/////////////wD//////////////////////////+QUAAAAAAAEuP//////////////AP/////////////////////////8QAAAAAAAAKT///////////////8A/////////////////////////4wAAAAAAAB0/////////////////wD////////////////////////cCAAAAAAANPz/////////////////AP///////////////////////0QAAAAAAATY//////////////////8A//////////////////////+0AAAAAAAAeP///////////////////wD//////////////////////CQAAAAAABTw////////////////////AP////////////////////+gAAAAAAAAkP////////////////////8A/////////////////////ywAAAAAABDw/////////////////////wD///////////////////+4AAAAAAAAbP//////////////////////AP///////////////////1wAAAAAAADQ//////////////////////8A///////////////////4DAAAAAAAMP///////////////////////wD//////////////////7QAAAAAAAB8////////////////////////AP//////////////////aAAAAAAAAMj///////////////////////8A//////////////////8oAAAAAAAM/P///////////////////////wD/////////////////8AAAAAAAAET/////////////////////////AP////////////////+0AAAAAAAAcP////////////////////////8A/////////////////4wAAAAAAACY/////////////////////////wD/////////////////WAAAAAAAAMD/////////////////////////AP////////////////80AAAAAAAA4P////////////////////////8A/////////////////xAAAAAAAAD4/////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=',
|
||||
'width' => 40
|
||||
),
|
||||
'8' => array(
|
||||
'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD////////////////////IdDQUAAAEIEiA1P//////////////////AP/////////////////gRAAAAAAAAAAAAAAAROD///////////////8A////////////////0BgAAAAAAAAAAAAAAAAAEMj//////////////wD///////////////AcAAAAAAAAAAAAAAAAAAAAHPD/////////////AP//////////////hAAAAAAAAAAAAAAAAAAAAAAAhP////////////8A//////////////8sAAAAAAAAKMz/zCgAAAAAAAAs/////////////wD//////////////wAAAAAAAADM////zAAAAAAAAAD/////////////AP//////////////BAAAAAAAAP//////AAAAAAAABP////////////8A//////////////8sAAAAAAAAzP///9QAAAAAAAAw/////////////wD//////////////3wAAAAAAAAoyP/YNAAAAAAAAIT/////////////AP//////////////7BgAAAAAAAAAAAAAAAAAAAAc8P////////////8A////////////////xBgAAAAAAAAAAAAAAAAAGNj//////////////wD/////////////////tAQAAAAAAAAAAAAAAACo////////////////AP///////////////HAAAAAAAAAAAAAAAAAAAAB8//////////////8A//////////////9gAAAAAAAAAAAAAAAAAAAAAAB8/////////////wD/////////////wAAAAAAAAABk4P/UWAAAAAAAAATQ////////////AP////////////9UAAAAAAAAaP//////XAAAAAAAAGT///////////8A/////////////xgAAAAAAADg///////cAAAAAAAAJP///////////wD/////////////AAAAAAAAAP////////8AAAAAAAAA////////////AP////////////8AAAAAAAAA4P//////3AAAAAAAAAT///////////8A/////////////ygAAAAAAABg//////9cAAAAAAAALP///////////wD/////////////ZAAAAAAAAABY1P/cXAAAAAAAAABw////////////AP/////////////QAAAAAAAAAAAAAAAAAAAAAAAABNz///////////8A//////////////9gAAAAAAAAAAAAAAAAAAAAAAB0/////////////wD///////////////Q8AAAAAAAAAAAAAAAAAAAAUPz/////////////AP////////////////x4CAAAAAAAAAAAAAAAEIT8//////////////8A///////////////////smFQwGAAAABg0ZKT0/////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=',
|
||||
'width' => 40
|
||||
),
|
||||
'9' => array(
|
||||
'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD///////////////////ysYCwMAAAUNGiw/P//////////////////AP////////////////+4JAAAAAAAAAAAAAAkuP////////////////8A////////////////lAQAAAAAAAAAAAAAAAAAkP///////////////wD//////////////8AEAAAAAAAAAAAAAAAAAAAAqP//////////////AP/////////////8JAAAAAAAAAAAAAAAAAAAAAAQ7P////////////8A/////////////6wAAAAAAAAAfOz8vCwAAAAAAABw/////////////wD/////////////WAAAAAAAAHD/////7BgAAAAAAAz4////////////AP////////////8kAAAAAAAA1P//////hAAAAAAAALT///////////8A/////////////wAAAAAAAAD///////+4AAAAAAAAcP///////////wD/////////////AAAAAAAAAPz//////8AAAAAAAABI////////////AP////////////8UAAAAAAAAzP//////lAAAAAAAACT///////////8A/////////////0QAAAAAAABY//////gsAAAAAAAADP///////////wD/////////////kAAAAAAAAABw5P/IPAAAAAAAAAAA////////////AP/////////////wEAAAAAAAAAAAAAAAAAAAAAAAAAD///////////8A//////////////+UAAAAAAAAAAAAAAAAAAAAAAAAAP///////////wD///////////////9wAAAAAAAAAAAAAFAAAAAAAAAU////////////AP////////////////+IBAAAAAAAAABw3AAAAAAAACj///////////8A///////////////////cdCwEABhcxP+8AAAAAAAATP///////////wD//////////////////////////////5AAAAAAAAB4////////////AP//////////////////////////////UAAAAAAAALj///////////8A//////////////+kgGxUQCAM2P///+AIAAAAAAAQ+P///////////wD//////////////0gAAAAAAAA42P/EKAAAAAAAAHD/////////////AP//////////////sAAAAAAAAAAAAAAAAAAAAAAQ6P////////////8A////////////////TAAAAAAAAAAAAAAAAAAAAKz//////////////wD////////////////oKAAAAAAAAAAAAAAAAASU////////////////AP/////////////////sUAAAAAAAAAAAAAAwxP////////////////8A////////////////////yHA0FAAADCxktP///////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=',
|
||||
'width' => 40
|
||||
),
|
||||
'A' => array(
|
||||
'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD//////////////////+QAAAAAAAAAAAAAAOT/////////////////AP//////////////////kAAAAAAAAAAAAAAAkP////////////////8A//////////////////88AAAAAAAAAAAAAAA8/////////////////wD/////////////////5AAAAAAAAAAAAAAAAADk////////////////AP////////////////+QAAAAAAAAAAAAAAAAAJD///////////////8A/////////////////zwAAAAAAAAAAAAAAAAAPP///////////////wD////////////////kAAAAAAAAAAgAAAAAAAAA5P//////////////AP///////////////5AAAAAAAAAAgAAAAAAAAACQ//////////////8A////////////////PAAAAAAAAAz8HAAAAAAAADz//////////////wD//////////////+QAAAAAAAAAWP9kAAAAAAAAANz/////////////AP//////////////kAAAAAAAAACk/7wAAAAAAAAAhP////////////8A//////////////88AAAAAAAABOz//BQAAAAAAAAw/////////////wD/////////////4AAAAAAAAAA8////ZAAAAAAAAADc////////////AP////////////+EAAAAAAAAAIj///+8AAAAAAAAAIT///////////8A/////////////zAAAAAAAAAA2P////wQAAAAAAAAMP///////////wD////////////cAAAAAAAAACT//////1wAAAAAAAAA3P//////////AP///////////4QAAAAAAAAAAAAAAAAAAAAAAAAAAACE//////////8A////////////MAAAAAAAAAAAAAAAAAAAAAAAAAAAADD//////////wD//////////9wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANz/////////AP//////////hAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAhP////////8A//////////8wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAw/////////wD/////////3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADc////////AP////////+EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIT///////8A/////////zAAAAAAAAAAhP///////////2QAAAAAAAAAMP///////wD////////cAAAAAAAAAADM////////////vAAAAAAAAAAA3P//////AP///////4QAAAAAAAAAHP/////////////4DAAAAAAAAACE//////8A////////MAAAAAAAAABk//////////////9cAAAAAAAAADD//////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=',
|
||||
'width' => 40
|
||||
),
|
||||
'B' => array(
|
||||
'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAEDh83P///////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAEhP//////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAeP////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAxP///////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAABY////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAABT///////////8A//////////8AAAAAAAAAAP/////4zEwAAAAAAAAAAP///////////wD//////////wAAAAAAAAAA////////7AAAAAAAAAAQ////////////AP//////////AAAAAAAAAAD////////sAAAAAAAAAEj///////////8A//////////8AAAAAAAAAAP/////4zEQAAAAAAAAAtP///////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAFz/////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAiA/P////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAIjPj//////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAGKz/////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAJT///////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAABNz//////////wD//////////wAAAAAAAAAA///////sqCAAAAAAAAAAbP//////////AP//////////AAAAAAAAAAD/////////yAAAAAAAAAAs//////////8A//////////8AAAAAAAAAAP//////////AAAAAAAAAAT//////////wD//////////wAAAAAAAAAA/////////7wAAAAAAAAAAP//////////AP//////////AAAAAAAAAAD//////+ikGAAAAAAAAAAY//////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFT//////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsP//////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAADj///////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAc6P///////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAATOj/////////////AP//////////AAAAAAAAAAAAAAAAAAAEIEBkkNj///////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=',
|
||||
'width' => 40
|
||||
),
|
||||
'C' => array(
|
||||
'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP//////////////////5JRULBAAAAgkTIDQ//////////////////8A////////////////1FAAAAAAAAAAAAAAAABAyP///////////////wD//////////////4gEAAAAAAAAAAAAAAAAAAAElP//////////////AP////////////9wAAAAAAAAAAAAAAAAAAAAAAAAlP////////////8A////////////kAAAAAAAAAAAAAAAAAAAAAAAAAAEyP///////////wD//////////9wIAAAAAAAAAAAAAAAAAAAAAAAAAAAw////////////AP//////////WAAAAAAAAAAAWMz/8JwQAAAAAAAAAACw//////////8A/////////+wEAAAAAAAAAID//////9QMAAAAAAAAAET//////////wD/////////nAAAAAAAAAAo/P///////3wAAAAABDBspP//////////AP////////9gAAAAAAAAAIz/////////3BxQjMT0//////////////8A/////////zQAAAAAAAAAzP///////////////////////////////wD/////////GAAAAAAAAADo////////////////////////////////AP////////8AAAAAAAAAAP////////////////////////////////8A/////////wAAAAAAAAAA/////////////////////////////////wD/////////AAAAAAAAAAD/////////////////////////////////AP////////8cAAAAAAAAAOj///////////////////////////////8A/////////zgAAAAAAAAA0P/////////kIGio7P///////////////wD/////////bAAAAAAAAACg/////////5wAAAAAMHS49P//////////AP////////+oAAAAAAAAAEz/////////PAAAAAAAAAAc//////////8A//////////QIAAAAAAAAALz//////6QAAAAAAAAAAGT//////////wD//////////3AAAAAAAAAADIzo/+SEBAAAAAAAAAAAyP//////////AP//////////7BAAAAAAAAAAAAAAAAAAAAAAAAAAAED///////////8A////////////rAAAAAAAAAAAAAAAAAAAAAAAAAAE0P///////////wD/////////////fAAAAAAAAAAAAAAAAAAAAAAAAJz/////////////AP//////////////iAQAAAAAAAAAAAAAAAAAAASY//////////////8A////////////////yEAAAAAAAAAAAAAAAAA8yP///////////////wD//////////////////9yIUCwQAAAAIEB4yP//////////////////AP////////////////////////////////////////////////////8=',
|
||||
'width' => 40
|
||||
),
|
||||
'D' => array(
|
||||
'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD///////////8AAAAAAAAAAAAAAAAADChQkOT/////////////////AP///////////wAAAAAAAAAAAAAAAAAAAAAABGjw//////////////8A////////////AAAAAAAAAAAAAAAAAAAAAAAAACDY/////////////wD///////////8AAAAAAAAAAAAAAAAAAAAAAAAAABjk////////////AP///////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAED///////////8A////////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAKj//////////wD///////////8AAAAAAAAAAP///+isSAAAAAAAAAAANP//////////AP///////////wAAAAAAAAAA////////hAAAAAAAAAAA2P////////8A////////////AAAAAAAAAAD/////////MAAAAAAAAACQ/////////wD///////////8AAAAAAAAAAP////////+MAAAAAAAAAFj/////////AP///////////wAAAAAAAAAA/////////8gAAAAAAAAAMP////////8A////////////AAAAAAAAAAD/////////5AAAAAAAAAAY/////////wD///////////8AAAAAAAAAAP//////////AAAAAAAAAAD/////////AP///////////wAAAAAAAAAA//////////8AAAAAAAAAAP////////8A////////////AAAAAAAAAAD//////////wAAAAAAAAAA/////////wD///////////8AAAAAAAAAAP/////////wAAAAAAAAABD/////////AP///////////wAAAAAAAAAA/////////9QAAAAAAAAAJP////////8A////////////AAAAAAAAAAD/////////qAAAAAAAAABI/////////wD///////////8AAAAAAAAAAP////////9QAAAAAAAAAHj/////////AP///////////wAAAAAAAAAA////////uAAAAAAAAAAAvP////////8A////////////AAAAAAAAAAD////w0HwEAAAAAAAAACT8/////////wD///////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAoP//////////AP///////////wAAAAAAAAAAAAAAAAAAAAAAAAAAADz8//////////8A////////////AAAAAAAAAAAAAAAAAAAAAAAAAAAY6P///////////wD///////////8AAAAAAAAAAAAAAAAAAAAAAAAAKNz/////////////AP///////////wAAAAAAAAAAAAAAAAAAAAAACHT0//////////////8A////////////AAAAAAAAAAAAAAAAABg4bKj0/////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=',
|
||||
'width' => 40
|
||||
),
|
||||
'E' => array(
|
||||
'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP//////////AAAAAAAAAAD///////////////////////////////8A//////////8AAAAAAAAAAP///////////////////////////////wD//////////wAAAAAAAAAA////////////////////////////////AP//////////AAAAAAAAAAD///////////////////////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAD//////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAA//////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAD//////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAA//////////////8A//////////8AAAAAAAAAAP///////////////////////////////wD//////////wAAAAAAAAAA////////////////////////////////AP//////////AAAAAAAAAAD///////////////////////////////8A//////////8AAAAAAAAAAP///////////////////////////////wD//////////wAAAAAAAAAA////////////////////////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP////////////////////////////////////////////////////8=',
|
||||
'width' => 40
|
||||
),
|
||||
'F' => array(
|
||||
'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAA////////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAD///////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAP///////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAA////////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAD///////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAP///////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=',
|
||||
'width' => 40
|
||||
),
|
||||
'G' => array(
|
||||
'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD//////////////////MB8TCgQAAAACCA4YJzs////////////////AP///////////////JQcAAAAAAAAAAAAAAAAAAhw8P////////////8A/////////////9gwAAAAAAAAAAAAAAAAAAAAAAAk2P///////////wD////////////EDAAAAAAAAAAAAAAAAAAAAAAAAAAc7P//////////AP//////////2AwAAAAAAAAAAAAAAAAAAAAAAAAAAABY//////////8A//////////wwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADQ/////////wD/////////kAAAAAAAAAAAEHzQ/P/gmCAAAAAAAAAAAFz/////////AP////////wcAAAAAAAAACjg////////8CwAAAAAAAAgWP////////8A////////vAAAAAAAAAAI2P//////////yBRAcJjI8P///////////wD///////94AAAAAAAAAGD/////////////////////////////////AP///////0AAAAAAAAAAsP////////////////////////////////8A////////IAAAAAAAAADc/////////////////////////////////wD///////8AAAAAAAAAAP///////wAAAAAAAAAAAAAAAAD/////////AP///////wAAAAAAAAAA////////AAAAAAAAAAAAAAAAAP////////8A////////AAAAAAAAAAD///////8AAAAAAAAAAAAAAAAA/////////wD///////8gAAAAAAAAAOD//////wAAAAAAAAAAAAAAAAD/////////AP///////0AAAAAAAAAAtP//////AAAAAAAAAAAAAAAAAP////////8A////////cAAAAAAAAABw//////8AAAAAAAAAAAAAAAAA/////////wD///////+8AAAAAAAAABDs////////////AAAAAAAAAAD/////////AP////////wYAAAAAAAAADz0//////////AAAAAAAAAAAP////////8A/////////5AAAAAAAAAAACCY4P//3KhcCAAAAAAAAAAA/////////wD/////////+CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////AP//////////xAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIP////////8A////////////rAQAAAAAAAAAAAAAAAAAAAAAAAAAAGTw/////////wD/////////////vBQAAAAAAAAAAAAAAAAAAAAAADjI////////////AP//////////////8HAQAAAAAAAAAAAAAAAAAEiw//////////////8A//////////////////iwcEAgBAAABCA4aKDk/////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=',
|
||||
'width' => 40
|
||||
),
|
||||
'H' => array(
|
||||
'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//////////8A/////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//////////8A/////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=',
|
||||
'width' => 40
|
||||
),
|
||||
'I' => array(
|
||||
'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAA////////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAD///////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAP///////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAA////////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAD///////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAP///////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAA////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAD///////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAP///////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAA////////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAD///////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAP///////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAA////////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAD///////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=',
|
||||
'width' => 40
|
||||
),
|
||||
'J' => array(
|
||||
'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP///////////////////////////wAAAAAAAAAA//////////////8A////////////////////////////AAAAAAAAAAD//////////////wD///////////////////////////8AAAAAAAAAAP//////////////AP///////////////////////////wAAAAAAAAAA//////////////8A////////////////////////////AAAAAAAAAAD//////////////wD///////////////////////////8AAAAAAAAAAP//////////////AP///////////////////////////wAAAAAAAAAA//////////////8A////////////////////////////AAAAAAAAAAD//////////////wD///////////////////////////8AAAAAAAAAAP//////////////AP///////////////////////////wAAAAAAAAAA//////////////8A////////////////////////////AAAAAAAAAAD//////////////wD///////////////////////////8AAAAAAAAAAP//////////////AP///////////////////////////wAAAAAAAAAA//////////////8A////////////////////////////AAAAAAAAAAD//////////////wD///////////////////////////8AAAAAAAAAAP//////////////AP///////////////////////////wAAAAAAAAAA//////////////8A////////////////////////////AAAAAAAAAAj//////////////wD//////////+zMrIxwUDAQ//////wAAAAAAAAAIP//////////////AP//////////DAAAAAAAAADo////2AAAAAAAAAA0//////////////8A//////////8wAAAAAAAAAKj///+YAAAAAAAAAFj//////////////wD//////////2gAAAAAAAAAIND/yBgAAAAAAAAAkP//////////////AP//////////vAAAAAAAAAAAAAAAAAAAAAAAAADc//////////////8A////////////MAAAAAAAAAAAAAAAAAAAAAAAUP///////////////wD////////////EBAAAAAAAAAAAAAAAAAAAABjk////////////////AP////////////+sBAAAAAAAAAAAAAAAAAAY2P////////////////8A///////////////EMAAAAAAAAAAAAAAAVOj//////////////////wD/////////////////vHBAIAAAABg8fNT/////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=',
|
||||
'width' => 40
|
||||
),
|
||||
'K' => array(
|
||||
'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD///////8AAAAAAAAAAP//////////wAQAAAAAAAAAAABw////////AP///////wAAAAAAAAAA/////////9AMAAAAAAAAAAAAcP////////8A////////AAAAAAAAAAD////////cGAAAAAAAAAAAAHD//////////wD///////8AAAAAAAAAAP//////6CgAAAAAAAAAAABs////////////AP///////wAAAAAAAAAA//////Q0AAAAAAAAAAAAVPz///////////8A////////AAAAAAAAAAD////8RAAAAAAAAAAAAFT8/////////////wD///////8AAAAAAAAAAP///1gAAAAAAAAAAABU/P//////////////AP///////wAAAAAAAAAA//9wAAAAAAAAAAAASPz///////////////8A////////AAAAAAAAAAD/jAAAAAAAAAAAADz0/////////////////wD///////8AAAAAAAAAAKQAAAAAAAAAAAA89P//////////////////AP///////wAAAAAAAAAABAAAAAAAAAAAFPT///////////////////8A////////AAAAAAAAAAAAAAAAAAAAAAAApP///////////////////wD///////8AAAAAAAAAAAAAAAAAAAAAAAAU8P//////////////////AP///////wAAAAAAAAAAAAAAAAAAAAAAAABk//////////////////8A////////AAAAAAAAAAAAAAAAAAAAAAAAAADE/////////////////wD///////8AAAAAAAAAAAAAAAAoEAAAAAAAACz8////////////////AP///////wAAAAAAAAAAAAAAGNiAAAAAAAAAAIj///////////////8A////////AAAAAAAAAAAAABjY//gYAAAAAAAACOD//////////////wD///////8AAAAAAAAAAAAY2P///5wAAAAAAAAASP//////////////AP///////wAAAAAAAAAAGNj//////CgAAAAAAAAAqP////////////8A////////AAAAAAAAAADI////////sAAAAAAAAAAc8P///////////wD///////8AAAAAAAAAAP//////////QAAAAAAAAABs////////////AP///////wAAAAAAAAAA///////////IAAAAAAAAAATI//////////8A////////AAAAAAAAAAD///////////9YAAAAAAAAADD8/////////wD///////8AAAAAAAAAAP///////////9wEAAAAAAAAAJD/////////AP///////wAAAAAAAAAA/////////////3AAAAAAAAAADOT///////8A////////AAAAAAAAAAD/////////////7BAAAAAAAAAAUP///////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=',
|
||||
'width' => 40
|
||||
),
|
||||
'L' => array(
|
||||
'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=',
|
||||
'width' => 40
|
||||
),
|
||||
'M' => array(
|
||||
'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A//////8AAAAAAAAAAAAAAHz//////3wAAAAAAAAAAAAAAP///////wD//////wAAAAAAAAAAAAAATP//////UAAAAAAAAAAAAAAA////////AP//////AAAAAAAAAAAAAAAc//////8cAAAAAAAAAAAAAAD///////8A//////8AAAAAAAAAAAAAAADw////8AAAAAAAAAAAAAAAAP///////wD//////wAAAAAAAAAAAAAAALz////AAAAAAAAAAAAAAAAA////////AP//////AAAAAAAAAAAAAAAAkP///5AAAAAAAAAAAAAAAAD///////8A//////8AAAAAAAAAAAAAAABc////ZAAAAAAAAAAAAAAAAP///////wD//////wAAAAAAAAAoAAAAADD///8wAAAAACQAAAAAAAAA////////AP//////AAAAAAAAAFwAAAAABPz//AgAAAAAXAAAAAAAAAD///////8A//////8AAAAAAAAAkAAAAAAA0P/UAAAAAACQAAAAAAAAAP///////wD//////wAAAAAAAADMAAAAAACg/6gAAAAAAMQAAAAAAAAA////////AP//////AAAAAAAAAPgEAAAAAHD/dAAAAAAE+AAAAAAAAAD///////8A//////8AAAAAAAAA/zQAAAAAQP9IAAAAADD/AAAAAAAAAP///////wD//////wAAAAAAAAD/bAAAAAAQ/xQAAAAAaP8AAAAAAAAA////////AP//////AAAAAAAAAP+gAAAAAADQAAAAAACc/wAAAAAAAAD///////8A//////8AAAAAAAAA/9QAAAAAAGgAAAAAAND/AAAAAAAAAP///////wD//////wAAAAAAAAD//wwAAAAAFAAAAAAM/P8AAAAAAAAA////////AP//////AAAAAAAAAP//RAAAAAAAAAAAADz//wAAAAAAAAD///////8A//////8AAAAAAAAA//94AAAAAAAAAAAAcP//AAAAAAAAAP///////wD//////wAAAAAAAAD//7AAAAAAAAAAAACo//8AAAAAAAAA////////AP//////AAAAAAAAAP//5AAAAAAAAAAAANz//wAAAAAAAAD///////8A//////8AAAAAAAAA////HAAAAAAAAAAQ////AAAAAAAAAP///////wD//////wAAAAAAAAD///9QAAAAAAAAAEz///8AAAAAAAAA////////AP//////AAAAAAAAAP///4gAAAAAAAAAfP///wAAAAAAAAD///////8A//////8AAAAAAAAA////vAAAAAAAAACw////AAAAAAAAAP///////wD//////wAAAAAAAAD////wAAAAAAAAAOz///8AAAAAAAAA////////AP//////AAAAAAAAAP////8sAAAAAAAc/////wAAAAAAAAD///////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=',
|
||||
'width' => 40
|
||||
),
|
||||
'N' => array(
|
||||
'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////AAAAAAAAALD/////////////AAAAAAAAAP//////////AP////////8AAAAAAAAAFOj///////////8AAAAAAAAA//////////8A/////////wAAAAAAAAAASP///////////wAAAAAAAAD//////////wD/////////AAAAAAAAAAAAkP//////////AAAAAAAAAP//////////AP////////8AAAAAAAAAAAAI1P////////8AAAAAAAAA//////////8A/////////wAAAAAAAAAAAAAw+P///////wAAAAAAAAD//////////wD/////////AAAAAAAAAAAAAABw////////AAAAAAAAAP//////////AP////////8AAAAAAAAAAAAAAAC8//////8AAAAAAAAA//////////8A/////////wAAAAAAAAAAAAAAABzs/////wAAAAAAAAD//////////wD/////////AAAAAAAAAAAAAAAAAFD/////AAAAAAAAAP//////////AP////////8AAAAAAAAAAAAAAAAAAJz///8AAAAAAAAA//////////8A/////////wAAAAAAAAAUAAAAAAAADNz//wAAAAAAAAD//////////wD/////////AAAAAAAAALQAAAAAAAAANPz/AAAAAAAAAP//////////AP////////8AAAAAAAAA/2wAAAAAAAAAfP8AAAAAAAAA//////////8A/////////wAAAAAAAAD/+CwAAAAAAAAExAAAAAAAAAD//////////wD/////////AAAAAAAAAP//0AQAAAAAAAAgAAAAAAAAAP//////////AP////////8AAAAAAAAA////jAAAAAAAAAAAAAAAAAAA//////////8A/////////wAAAAAAAAD/////RAAAAAAAAAAAAAAAAAD//////////wD/////////AAAAAAAAAP/////kFAAAAAAAAAAAAAAAAP//////////AP////////8AAAAAAAAA//////+sAAAAAAAAAAAAAAAA//////////8A/////////wAAAAAAAAD///////9kAAAAAAAAAAAAAAD//////////wD/////////AAAAAAAAAP////////QkAAAAAAAAAAAAAP//////////AP////////8AAAAAAAAA/////////8wEAAAAAAAAAAAA//////////8A/////////wAAAAAAAAD//////////4QAAAAAAAAAAAD//////////wD/////////AAAAAAAAAP///////////DwAAAAAAAAAAP//////////AP////////8AAAAAAAAA////////////4BAAAAAAAAAA//////////8A/////////wAAAAAAAAD/////////////qAAAAAAAAAD//////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=',
|
||||
'width' => 40
|
||||
),
|
||||
'O' => array(
|
||||
'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A///////////////////0qGw4HAAAABw4aKT0/////////////////wD////////////////wcAwAAAAAAAAAAAAAAAho6P//////////////AP//////////////uBQAAAAAAAAAAAAAAAAAAAAMoP////////////8A/////////////6AEAAAAAAAAAAAAAAAAAAAAAAAAkP///////////wD///////////+4BAAAAAAAAAAAAAAAAAAAAAAAAAAAoP//////////AP//////////8BQAAAAAAAAAAAAAAAAAAAAAAAAAAAAM5P////////8A//////////9wAAAAAAAAAAAsrPD/7KQsAAAAAAAAAABg/////////wD/////////+BAAAAAAAAAAUPj///////hQAAAAAAAAAAjs////////AP////////+sAAAAAAAAABDw//////////AYAAAAAAAAAKD///////8A/////////2wAAAAAAAAAdP///////////3wAAAAAAAAAYP///////wD/////////OAAAAAAAAAC4////////////xAAAAAAAAAAw////////AP////////8cAAAAAAAAAOD////////////oAAAAAAAAABT///////8A/////////wAAAAAAAAAA//////////////8AAAAAAAAAAP///////wD/////////AAAAAAAAAAD//////////////wAAAAAAAAAA////////AP////////8AAAAAAAAAAP/////////////8AAAAAAAAAAD///////8A/////////xwAAAAAAAAA5P///////////+AAAAAAAAAAHP///////wD/////////NAAAAAAAAAC8////////////uAAAAAAAAAA4////////AP////////9oAAAAAAAAAHj///////////98AAAAAAAAAGT///////8A/////////6gAAAAAAAAAGPD/////////+BgAAAAAAAAApP///////wD/////////9AwAAAAAAAAAUPz///////xcAAAAAAAAAAjs////////AP//////////cAAAAAAAAAAALKjs//CwOAAAAAAAAAAAYP////////8A///////////wFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzk/////////wD///////////+4BAAAAAAAAAAAAAAAAAAAAAAAAAAAoP//////////AP////////////+QAAAAAAAAAAAAAAAAAAAAAAAAAJD///////////8A//////////////+sEAAAAAAAAAAAAAAAAAAAAAyg/////////////wD////////////////oZAgAAAAAAAAAAAAAAARg4P//////////////AP//////////////////9KhsOCAAAAAUMFyc7P////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=',
|
||||
'width' => 40
|
||||
),
|
||||
'P' => array(
|
||||
'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP///////////wAAAAAAAAAAAAAAAAAACCxguP////////////////8A////////////AAAAAAAAAAAAAAAAAAAAAAAAOOD//////////////wD///////////8AAAAAAAAAAAAAAAAAAAAAAAAAGOD/////////////AP///////////wAAAAAAAAAAAAAAAAAAAAAAAAAARP////////////8A////////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAxP///////////wD///////////8AAAAAAAAAAAAAAAAAAAAAAAAAAABo////////////AP///////////wAAAAAAAAAA////6JwMAAAAAAAAADD///////////8A////////////AAAAAAAAAAD//////6AAAAAAAAAADP///////////wD///////////8AAAAAAAAAAP//////9AAAAAAAAAAA////////////AP///////////wAAAAAAAAAA///////0AAAAAAAAAAD///////////8A////////////AAAAAAAAAAD//////5gAAAAAAAAAHP///////////wD///////////8AAAAAAAAAAP///9iICAAAAAAAAABI////////////AP///////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAJD///////////8A////////////AAAAAAAAAAAAAAAAAAAAAAAAAAAI6P///////////wD///////////8AAAAAAAAAAAAAAAAAAAAAAAAAAIT/////////////AP///////////wAAAAAAAAAAAAAAAAAAAAAAAABU/P////////////8A////////////AAAAAAAAAAAAAAAAAAAAAAAIhPz//////////////wD///////////8AAAAAAAAAAAAAAAAABCRMkOz/////////////////AP///////////wAAAAAAAAAA//////////////////////////////8A////////////AAAAAAAAAAD//////////////////////////////wD///////////8AAAAAAAAAAP//////////////////////////////AP///////////wAAAAAAAAAA//////////////////////////////8A////////////AAAAAAAAAAD//////////////////////////////wD///////////8AAAAAAAAAAP//////////////////////////////AP///////////wAAAAAAAAAA//////////////////////////////8A////////////AAAAAAAAAAD//////////////////////////////wD///////////8AAAAAAAAAAP//////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=',
|
||||
'width' => 40
|
||||
),
|
||||
'Q' => array(
|
||||
'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////SoaDQcAAAAHDhoqPT///////////////////8A//////////////BwDAAAAAAAAAAAAAAACHDo/////////////////wD///////////+4FAAAAAAAAAAAAAAAAAAAABCo////////////////AP//////////nAQAAAAAAAAAAAAAAAAAAAAAAACQ//////////////8A/////////7gEAAAAAAAAAAAAAAAAAAAAAAAAAACg/////////////wD////////wFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzo////////////AP///////3AAAAAAAAAAACyo8P/sqCwAAAAAAAAAAGT///////////8A///////4EAAAAAAAAABM+P///////FQAAAAAAAAACPT//////////wD//////7AAAAAAAAAAFPD/////////9BgAAAAAAAAApP//////////AP//////bAAAAAAAAAB4////////////fAAAAAAAAABk//////////8A//////84AAAAAAAAALz///////////+8AAAAAAAAADT//////////wD//////xwAAAAAAAAA6P///////////+QAAAAAAAAAHP//////////AP//////AAAAAAAAAAD//////////////wAAAAAAAAAA//////////8A//////8AAAAAAAAAAP//////////////AAAAAAAAAAD//////////wD//////wAAAAAAAAAA/P////////////8AAAAAAAAAAP//////////AP//////GAAAAAAAAADg////////////4AAAAAAAAAAc//////////8A//////84AAAAAAAAALT////MJHTo//+8AAAAAAAAADT//////////wD//////2wAAAAAAAAAdP///2AAABCg/3wAAAAAAAAAZP//////////AP//////rAAAAAAAAAAY9P/sCAAAAABMGAAAAAAAAACk//////////8A///////4EAAAAAAAAABU/P+0OAAAAAAAAAAAAAAACPT//////////wD///////94AAAAAAAAAAA4sPD/gAAAAAAAAAAAAABk////////////AP////////AcAAAAAAAAAAAAAAAAAAAAAAAAAAAADOT///////////8A/////////7wEAAAAAAAAAAAAAAAAAAAAAAAAAACQ/////////////wD//////////6wEAAAAAAAAAAAAAAAAAAAAAAAAABSs////////////AP///////////7gUAAAAAAAAAAAAAAAAAAAAAAAAAABAwP////////8A//////////////BwDAAAAAAAAAAAAAAABAgAAAAAAAA8/////////wD////////////////0qGg0GAAAABgwXJjkxBgAAAAAALD/////////AP//////////////////////////////////5DQAAAAk/P////////8A////////////////////////////////////+GwAAJD//////////wD//////////////////////////////////////8A49P//////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=',
|
||||
'width' => 40
|
||||
),
|
||||
'R' => array(
|
||||
'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////wAAAAAAAAAAAAAAAAAAAAQgOGSk+P///////////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAAcuP//////////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAEsP////////////8A/////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQ6P///////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB8////////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAADD///////////8A/////////wAAAAAAAAAA///////svDgAAAAAAAAACP///////////wD/////////AAAAAAAAAAD/////////7AAAAAAAAAAA////////////AP////////8AAAAAAAAAAP/////////cAAAAAAAAABD///////////8A/////////wAAAAAAAAAA//////DQoCQAAAAAAAAAQP///////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAACU////////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAIPj///////////8A/////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAzU/////////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAA02P//////////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAxctPz///////////////8A/////////wAAAAAAAAAAAAAAAAAAAAAAAEDY/////////////////wD/////////AAAAAAAAAAD/9LAsAAAAAAAAAAzc////////////////AP////////8AAAAAAAAAAP///+wkAAAAAAAAADD8//////////////8A/////////wAAAAAAAAAA/////8QAAAAAAAAAAJD//////////////wD/////////AAAAAAAAAAD//////1QAAAAAAAAAFPD/////////////AP////////8AAAAAAAAAAP//////3AQAAAAAAAAAgP////////////8A/////////wAAAAAAAAAA////////aAAAAAAAAAAM6P///////////wD/////////AAAAAAAAAAD////////oCAAAAAAAAABs////////////AP////////8AAAAAAAAAAP////////+AAAAAAAAAAATc//////////8A/////////wAAAAAAAAAA//////////AUAAAAAAAAAFj//////////wD/////////AAAAAAAAAAD//////////5AAAAAAAAAAAND/////////AP////////8AAAAAAAAAAP//////////+CQAAAAAAAAAQP////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=',
|
||||
'width' => 40
|
||||
),
|
||||
'S' => array(
|
||||
'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP/////////////////8vHBEIAgAAAQgQHC8/P////////////////8A////////////////pCQAAAAAAAAAAAAAAAAcoP///////////////wD//////////////FwAAAAAAAAAAAAAAAAAAAAAXP//////////////AP////////////9oAAAAAAAAAAAAAAAAAAAAAAAAhP////////////8A////////////zAAAAAAAAAAAAAAAAAAAAAAAAAAI6P///////////wD///////////9cAAAAAAAAAAAAAAAAAAAAAAAAAACA////////////AP///////////xgAAAAAAAAAUOD/8KwkAAAAAAAAADj///////////8A////////////AAAAAAAAAAD0/////8wABCAgICxASP///////////wD///////////8MAAAAAAAAAMz/////////////////////////////AP///////////0AAAAAAAAAACFiQxPT///////////////////////8A////////////oAAAAAAAAAAAAAAAADBwtPT//////////////////wD////////////8QAAAAAAAAAAAAAAAAAAACFTA////////////////AP/////////////oOAAAAAAAAAAAAAAAAAAAAABM6P////////////8A///////////////4fAgAAAAAAAAAAAAAAAAAAAAY2P///////////wD/////////////////7IwwAAAAAAAAAAAAAAAAAAAo+P//////////AP/////////////////////koGw0BAAAAAAAAAAAAACU//////////8A///////////////////////////4uFgAAAAAAAAAADz//////////wD//////////2BgSEA0IBwA6P///////5QAAAAAAAAADP//////////AP//////////JAAAAAAAAACc/////////AAAAAAAAAAA//////////8A//////////9YAAAAAAAAACDo///////AAAAAAAAAABT//////////wD//////////6QAAAAAAAAAACCk7P/snBQAAAAAAAAAUP//////////AP//////////+BAAAAAAAAAAAAAAAAAAAAAAAAAAAACs//////////8A////////////kAAAAAAAAAAAAAAAAAAAAAAAAAAAOP///////////wD////////////8RAAAAAAAAAAAAAAAAAAAAAAAABjc////////////AP/////////////0PAAAAAAAAAAAAAAAAAAAAAAg2P////////////8A///////////////8hBQAAAAAAAAAAAAAAAAMdPT//////////////wD/////////////////+LRwSCAMAAAAHDhoqPT/////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=',
|
||||
'width' => 40
|
||||
),
|
||||
'T' => array(
|
||||
'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////////8A/////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////////8A/////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=',
|
||||
'width' => 40
|
||||
),
|
||||
'U' => array(
|
||||
'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////JAAAAAAAAADk/////////+gAAAAAAAAAHP//////////AP////////9MAAAAAAAAAJz/////////nAAAAAAAAABE//////////8A/////////4gAAAAAAAAAHOj//////+ggAAAAAAAAAHz//////////wD/////////0AAAAAAAAAAAIJzs/+ykIAAAAAAAAAAA0P//////////AP//////////QAAAAAAAAAAAAAAAAAAAAAAAAAAAAED///////////8A///////////IBAAAAAAAAAAAAAAAAAAAAAAAAAAE0P///////////wD///////////+YAAAAAAAAAAAAAAAAAAAAAAAAAJj/////////////AP////////////+UBAAAAAAAAAAAAAAAAAAAAASU//////////////8A///////////////IPAAAAAAAAAAAAAAAAAAwyP///////////////wD/////////////////0IxYOCAIAAAEIEiAyP//////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=',
|
||||
'width' => 40
|
||||
),
|
||||
'V' => array(
|
||||
'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD//////zAAAAAAAAAAYP//////////////ZAAAAAAAAAAw////////AP//////kAAAAAAAAAAU/P////////////8UAAAAAAAAAJD///////8A///////oBAAAAAAAAADE////////////xAAAAAAAAAAE7P///////wD///////9MAAAAAAAAAHD///////////94AAAAAAAAAEz/////////AP///////6gAAAAAAAAAJP///////////yQAAAAAAAAArP////////8A////////+BAAAAAAAAAA1P/////////YAAAAAAAAABT4/////////wD/////////aAAAAAAAAACE/////////4QAAAAAAAAAbP//////////AP/////////EAAAAAAAAADT/////////OAAAAAAAAADM//////////8A//////////8kAAAAAAAAAOT//////+QAAAAAAAAAKP///////////wD//////////4QAAAAAAAAAmP//////nAAAAAAAAACI////////////AP//////////5AAAAAAAAABE//////9EAAAAAAAABOT///////////8A////////////QAAAAAAAAAT0////9AgAAAAAAABI/////////////wD///////////+gAAAAAAAAAKT///+kAAAAAAAAAKj/////////////AP////////////QIAAAAAAAAXP///1wAAAAAAAAM+P////////////8A/////////////1wAAAAAAAAM+P/8DAAAAAAAAGT//////////////wD/////////////vAAAAAAAAAC8/7wAAAAAAAAAxP//////////////AP//////////////HAAAAAAAAGj/aAAAAAAAACT///////////////8A//////////////94AAAAAAAAHP8cAAAAAAAAhP///////////////wD//////////////9gAAAAAAAAAkAAAAAAAAADk////////////////AP///////////////zgAAAAAAAAQAAAAAAAAQP////////////////8A////////////////lAAAAAAAAAAAAAAAAACg/////////////////wD////////////////sCAAAAAAAAAAAAAAADPT/////////////////AP////////////////9QAAAAAAAAAAAAAABg//////////////////8A/////////////////7AAAAAAAAAAAAAAAMD//////////////////wD//////////////////BQAAAAAAAAAAAAc////////////////////AP//////////////////cAAAAAAAAAAAAHz///////////////////8A///////////////////MAAAAAAAAAAAA3P///////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=',
|
||||
'width' => 40
|
||||
),
|
||||
'W' => array(
|
||||
'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A//8cAAAAAAAAALz/////4AAAAAAAAAAA6P////+8AAAAAAAAABz//wD//1QAAAAAAAAAjP////+gAAAAAAAAAACo/////4wAAAAAAAAAUP//AP//jAAAAAAAAABU/////2AAAAAAAAAAAGj/////VAAAAAAAAACM//8A///EAAAAAAAAACT/////IAAAAAAAAAAAKP////8kAAAAAAAAAMT//wD///gEAAAAAAAAAPD//+AAAAAAAAAAAAAA6P//8AAAAAAAAAAE9P//AP///zAAAAAAAAAAvP//oAAAAAAAAAAAAACo//+8AAAAAAAAADD///8A////bAAAAAAAAACM//9gAAAAAAAAAAAAAGT//4wAAAAAAAAAaP///wD///+kAAAAAAAAAFT//yAAAAAAAAAAAAAAIP//VAAAAAAAAACc////AP///9gAAAAAAAAAJP/gAAAAAAAAAAAAAAAA4P8kAAAAAAAAANT///8A/////xAAAAAAAAAA8KAAAAAAAAAAAAAAAACg8AAAAAAAAAAQ/////wD/////TAAAAAAAAAC8YAAAAAAAAAAAAAAAAGC8AAAAAAAAAET/////AP////+AAAAAAAAAAIwgAAAAAAAAAAAAAAAAIIwAAAAAAAAAfP////8A/////7gAAAAAAAAANAAAAAAAACwwAAAAAAAANAAAAAAAAACw/////wD/////8AAAAAAAAAAAAAAAAAAAdHgAAAAAAAAAAAAAAAAAAOz/////AP//////KAAAAAAAAAAAAAAAAAC4vAAAAAAAAAAAAAAAAAAg//////8A//////9gAAAAAAAAAAAAAAAACPj4CAAAAAAAAAAAAAAAAFj//////wD//////5QAAAAAAAAAAAAAAABE//9IAAAAAAAAAAAAAAAAkP//////AP//////0AAAAAAAAAAAAAAAAIj//4wAAAAAAAAAAAAAAADI//////8A///////8DAAAAAAAAAAAAAAAzP//1AAAAAAAAAAAAAAABPj//////wD///////88AAAAAAAAAAAAABT/////GAAAAAAAAAAAAAA0////////AP///////3QAAAAAAAAAAAAAWP////9gAAAAAAAAAAAAAHD///////8A////////sAAAAAAAAAAAAACg/////6QAAAAAAAAAAAAApP///////wD////////kAAAAAAAAAAAAAOT/////6AAAAAAAAAAAAADc////////AP////////8cAAAAAAAAAAAo////////MAAAAAAAAAAAEP////////8A/////////1QAAAAAAAAAAHD///////94AAAAAAAAAABM/////////wD/////////jAAAAAAAAAAAtP///////7wAAAAAAAAAAID/////////AP/////////EAAAAAAAAAAT0////////+AgAAAAAAAAAuP////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=',
|
||||
'width' => 40
|
||||
),
|
||||
'X' => array(
|
||||
'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD///////9UAAAAAAAAAKz///////////+sAAAAAAAAAFD/////////AP///////+QQAAAAAAAAFOT/////////8BwAAAAAAAAM5P////////8A/////////5gAAAAAAAAATP////////9kAAAAAAAAAJD//////////wD//////////0AAAAAAAAAAoP//////wAAAAAAAAAA0/P//////////AP//////////2AgAAAAAAAAQ4P////gkAAAAAAAABMz///////////8A////////////iAAAAAAAAABA////dAAAAAAAAABw/////////////wD////////////8MAAAAAAAAACU/9AEAAAAAAAAHPD/////////////AP/////////////IBAAAAAAAAAzYMAAAAAAAAACs//////////////8A//////////////90AAAAAAAAABAAAAAAAAAATP///////////////wD///////////////QgAAAAAAAAAAAAAAAAAAzg////////////////AP///////////////7wAAAAAAAAAAAAAAAAAjP////////////////8A/////////////////2AAAAAAAAAAAAAAADD8/////////////////wD/////////////////7BQAAAAAAAAAAAAEyP//////////////////AP/////////////////gDAAAAAAAAAAAAAjY//////////////////8A/////////////////0AAAAAAAAAAAAAAADj8/////////////////wD///////////////+UAAAAAAAAAAAAAAAAAJD/////////////////AP//////////////4AwAAAAAAAAAAAAAAAAADOD///////////////8A//////////////9AAAAAAAAAAAAAAAAAAAAAQP///////////////wD/////////////nAAAAAAAAAAAWAAAAAAAAAAAlP//////////////AP///////////+QQAAAAAAAAAGD/YAAAAAAAAAAM4P////////////8A////////////TAAAAAAAAAAs9P/0LAAAAAAAAABM/////////////wD//////////6AAAAAAAAAADNT////UDAAAAAAAAACg////////////AP/////////kEAAAAAAAAACg//////+gAAAAAAAAABDk//////////8A/////////0wAAAAAAAAAYP////////9gAAAAAAAAAEz//////////wD///////+oAAAAAAAAACz0//////////QsAAAAAAAAAKT/////////AP//////7BQAAAAAAAAM1P///////////9QMAAAAAAAAFOz///////8A//////9UAAAAAAAAAKD//////////////6AAAAAAAAAAVP///////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=',
|
||||
'width' => 40
|
||||
),
|
||||
'Y' => array(
|
||||
'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP///////1QAAAAAAAAAAGj//////////2gAAAAAAAAAAFT///////8A////////5BAAAAAAAAAAAMT////////EAAAAAAAAAAAQ5P///////wD/////////mAAAAAAAAAAAKPj/////+CgAAAAAAAAAAJj/////////AP//////////PAAAAAAAAAAAgP////+AAAAAAAAAAAA8//////////8A///////////YCAAAAAAAAAAE2P//2AQAAAAAAAAACNj//////////wD///////////+AAAAAAAAAAAA4//84AAAAAAAAAACA////////////AP////////////woAAAAAAAAAACUlAAAAAAAAAAAKPz///////////8A/////////////8gAAAAAAAAAABAQAAAAAAAAAADI/////////////wD//////////////2wAAAAAAAAAAAAAAAAAAAAAbP//////////////AP//////////////8BwAAAAAAAAAAAAAAAAAABzw//////////////8A////////////////tAAAAAAAAAAAAAAAAAAAtP///////////////wD/////////////////VAAAAAAAAAAAAAAAAFT/////////////////AP/////////////////oEAAAAAAAAAAAAAAQ6P////////////////8A//////////////////+cAAAAAAAAAAAAAJz//////////////////wD///////////////////9AAAAAAAAAAABA////////////////////AP///////////////////9gAAAAAAAAAANj///////////////////8A/////////////////////wAAAAAAAAAA/////////////////////wD/////////////////////AAAAAAAAAAD/////////////////////AP////////////////////8AAAAAAAAAAP////////////////////8A/////////////////////wAAAAAAAAAA/////////////////////wD/////////////////////AAAAAAAAAAD/////////////////////AP////////////////////8AAAAAAAAAAP////////////////////8A/////////////////////wAAAAAAAAAA/////////////////////wD/////////////////////AAAAAAAAAAD/////////////////////AP////////////////////8AAAAAAAAAAP////////////////////8A/////////////////////wAAAAAAAAAA/////////////////////wD/////////////////////AAAAAAAAAAD/////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=',
|
||||
'width' => 40
|
||||
),
|
||||
'Z' => array(
|
||||
'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAD//////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAA//////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAD//////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAQ//////////////8A/////////////////////////1AAAAAAAAAABLz//////////////wD///////////////////////98AAAAAAAAAACY////////////////AP//////////////////////pAAAAAAAAAAAaP////////////////8A/////////////////////8QIAAAAAAAAAET8/////////////////wD////////////////////gGAAAAAAAAAAo9P//////////////////AP//////////////////9CwAAAAAAAAAFNz///////////////////8A//////////////////xMAAAAAAAAAATA/////////////////////wD/////////////////eAAAAAAAAAAAnP//////////////////////AP///////////////5wAAAAAAAAAAHT///////////////////////8A///////////////ABAAAAAAAAABM/P///////////////////////wD/////////////3BQAAAAAAAAALPT/////////////////////////AP////////////QoAAAAAAAAABjg//////////////////////////8A///////////8SAAAAAAAAAAExP///////////////////////////wD//////////2wAAAAAAAAAAKD/////////////////////////////AP////////+YAAAAAAAAAAB8//////////////////////////////8A/////////wQAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A/////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=',
|
||||
'width' => 40
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
390
phpbb/captcha/plugins/captcha_abstract.php
Normal file
390
phpbb/captcha/plugins/captcha_abstract.php
Normal file
@@ -0,0 +1,390 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\captcha\plugins;
|
||||
|
||||
/**
|
||||
* This class holds the code shared by the two default 3.0.x CAPTCHAs.
|
||||
*/
|
||||
abstract class captcha_abstract
|
||||
{
|
||||
var $confirm_id;
|
||||
var $confirm_code;
|
||||
var $code;
|
||||
var $seed;
|
||||
var $attempts = 0;
|
||||
var $type;
|
||||
var $solved = 0;
|
||||
var $captcha_vars = false;
|
||||
|
||||
/**
|
||||
* @var string name of the service.
|
||||
*/
|
||||
protected $service_name;
|
||||
|
||||
function init($type)
|
||||
{
|
||||
global $config, $request;
|
||||
|
||||
// read input
|
||||
$this->confirm_id = $request->variable('confirm_id', '');
|
||||
$this->confirm_code = $request->variable('confirm_code', '');
|
||||
$refresh = $request->variable('refresh_vc', false) && $config['confirm_refresh'];
|
||||
|
||||
$this->type = (int) $type;
|
||||
|
||||
if (!strlen($this->confirm_id) || !$this->load_code())
|
||||
{
|
||||
// we have no confirm ID, better get ready to display something
|
||||
$this->generate_code();
|
||||
}
|
||||
else if ($refresh)
|
||||
{
|
||||
$this->regenerate_code();
|
||||
}
|
||||
}
|
||||
|
||||
function execute_demo()
|
||||
{
|
||||
$this->code = gen_rand_string_friendly(mt_rand(CAPTCHA_MIN_CHARS, CAPTCHA_MAX_CHARS));
|
||||
$this->seed = hexdec(substr(unique_id(), 4, 10));
|
||||
|
||||
// compute $seed % 0x7fffffff
|
||||
$this->seed -= 0x7fffffff * floor($this->seed / 0x7fffffff);
|
||||
|
||||
$generator = $this->get_generator_class();
|
||||
$captcha = new $generator();
|
||||
define('IMAGE_OUTPUT', 1);
|
||||
$captcha->execute($this->code, $this->seed);
|
||||
}
|
||||
|
||||
function execute()
|
||||
{
|
||||
if (empty($this->code))
|
||||
{
|
||||
if (!$this->load_code())
|
||||
{
|
||||
// invalid request, bail out
|
||||
return false;
|
||||
}
|
||||
}
|
||||
$generator = $this->get_generator_class();
|
||||
$captcha = new $generator();
|
||||
define('IMAGE_OUTPUT', 1);
|
||||
$captcha->execute($this->code, $this->seed);
|
||||
}
|
||||
|
||||
function get_template()
|
||||
{
|
||||
global $config, $user, $template, $phpEx, $phpbb_root_path;
|
||||
|
||||
if ($this->is_solved())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
$link = append_sid($phpbb_root_path . 'ucp.' . $phpEx, 'mode=confirm&confirm_id=' . $this->confirm_id . '&type=' . $this->type);
|
||||
$contact_link = phpbb_get_board_contact_link($config, $phpbb_root_path, $phpEx);
|
||||
$explain = $user->lang(($this->type != CONFIRM_POST) ? 'CONFIRM_EXPLAIN' : 'POST_CONFIRM_EXPLAIN', '<a href="' . $contact_link . '">', '</a>');
|
||||
|
||||
$template->assign_vars(array(
|
||||
'CONFIRM_IMAGE_LINK' => $link,
|
||||
'CONFIRM_IMAGE' => '<img src="' . $link . '" />',
|
||||
'CONFIRM_IMG' => '<img src="' . $link . '" />',
|
||||
'CONFIRM_ID' => $this->confirm_id,
|
||||
'S_CONFIRM_CODE' => true,
|
||||
'S_TYPE' => $this->type,
|
||||
'S_CONFIRM_REFRESH' => ($config['enable_confirm'] && $config['confirm_refresh'] && $this->type == CONFIRM_REG) ? true : false,
|
||||
'L_CONFIRM_EXPLAIN' => $explain,
|
||||
));
|
||||
|
||||
return 'captcha_default.html';
|
||||
}
|
||||
}
|
||||
|
||||
function get_demo_template($id)
|
||||
{
|
||||
global $config, $template, $request, $phpbb_admin_path, $phpEx;
|
||||
|
||||
$variables = '';
|
||||
|
||||
if (is_array($this->captcha_vars))
|
||||
{
|
||||
foreach ($this->captcha_vars as $captcha_var => $template_var)
|
||||
{
|
||||
$variables .= '&' . rawurlencode($captcha_var) . '=' . $request->variable($captcha_var, (int) $config[$captcha_var]);
|
||||
}
|
||||
}
|
||||
|
||||
// acp_captcha has a delivery function; let's use it
|
||||
$template->assign_vars(array(
|
||||
'CONFIRM_IMAGE' => append_sid($phpbb_admin_path . 'index.' . $phpEx, 'captcha_demo=1&mode=visual&i=' . $id . '&select_captcha=' . $this->get_service_name()) . $variables,
|
||||
'CONFIRM_ID' => $this->confirm_id,
|
||||
));
|
||||
|
||||
return 'captcha_default_acp_demo.html';
|
||||
}
|
||||
|
||||
function get_hidden_fields()
|
||||
{
|
||||
$hidden_fields = array();
|
||||
|
||||
// this is required for posting.php - otherwise we would forget about the captcha being already solved
|
||||
if ($this->solved)
|
||||
{
|
||||
$hidden_fields['confirm_code'] = $this->confirm_code;
|
||||
}
|
||||
$hidden_fields['confirm_id'] = $this->confirm_id;
|
||||
return $hidden_fields;
|
||||
}
|
||||
|
||||
function garbage_collect($type)
|
||||
{
|
||||
global $db;
|
||||
|
||||
$sql = 'SELECT DISTINCT c.session_id
|
||||
FROM ' . CONFIRM_TABLE . ' c
|
||||
LEFT JOIN ' . SESSIONS_TABLE . ' s ON (c.session_id = s.session_id)
|
||||
WHERE s.session_id IS NULL' .
|
||||
((empty($type)) ? '' : ' AND c.confirm_type = ' . (int) $type);
|
||||
$result = $db->sql_query($sql);
|
||||
|
||||
if ($row = $db->sql_fetchrow($result))
|
||||
{
|
||||
$sql_in = array();
|
||||
do
|
||||
{
|
||||
$sql_in[] = (string) $row['session_id'];
|
||||
}
|
||||
while ($row = $db->sql_fetchrow($result));
|
||||
|
||||
if (count($sql_in))
|
||||
{
|
||||
$sql = 'DELETE FROM ' . CONFIRM_TABLE . '
|
||||
WHERE ' . $db->sql_in_set('session_id', $sql_in);
|
||||
$db->sql_query($sql);
|
||||
}
|
||||
}
|
||||
$db->sql_freeresult($result);
|
||||
}
|
||||
|
||||
function uninstall()
|
||||
{
|
||||
$this->garbage_collect(0);
|
||||
}
|
||||
|
||||
function install()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
function validate()
|
||||
{
|
||||
global $user;
|
||||
|
||||
if (!$user->is_setup())
|
||||
{
|
||||
$user->setup();
|
||||
}
|
||||
|
||||
$error = '';
|
||||
if (!$this->confirm_id)
|
||||
{
|
||||
$error = $user->lang['CONFIRM_CODE_WRONG'];
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($this->check_code())
|
||||
{
|
||||
$this->solved = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
$error = $user->lang['CONFIRM_CODE_WRONG'];
|
||||
}
|
||||
}
|
||||
|
||||
if (strlen($error))
|
||||
{
|
||||
// okay, incorrect answer. Let's ask a new question.
|
||||
$this->new_attempt();
|
||||
return $error;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The old way to generate code, suitable for GD and non-GD. Resets the internal state.
|
||||
*/
|
||||
function generate_code()
|
||||
{
|
||||
global $db, $user;
|
||||
|
||||
$this->code = gen_rand_string_friendly(mt_rand(CAPTCHA_MIN_CHARS, CAPTCHA_MAX_CHARS));
|
||||
$this->confirm_id = md5(unique_id($user->ip));
|
||||
$this->seed = hexdec(substr(unique_id(), 4, 10));
|
||||
$this->solved = 0;
|
||||
// compute $seed % 0x7fffffff
|
||||
$this->seed -= 0x7fffffff * floor($this->seed / 0x7fffffff);
|
||||
|
||||
$sql = 'INSERT INTO ' . CONFIRM_TABLE . ' ' . $db->sql_build_array('INSERT', array(
|
||||
'confirm_id' => (string) $this->confirm_id,
|
||||
'session_id' => (string) $user->session_id,
|
||||
'confirm_type' => (int) $this->type,
|
||||
'code' => (string) $this->code,
|
||||
'seed' => (int) $this->seed)
|
||||
);
|
||||
$db->sql_query($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* New Question, if desired.
|
||||
*/
|
||||
function regenerate_code()
|
||||
{
|
||||
global $db, $user;
|
||||
|
||||
$this->code = gen_rand_string_friendly(mt_rand(CAPTCHA_MIN_CHARS, CAPTCHA_MAX_CHARS));
|
||||
$this->seed = hexdec(substr(unique_id(), 4, 10));
|
||||
$this->solved = 0;
|
||||
// compute $seed % 0x7fffffff
|
||||
$this->seed -= 0x7fffffff * floor($this->seed / 0x7fffffff);
|
||||
|
||||
$sql = 'UPDATE ' . CONFIRM_TABLE . ' SET ' . $db->sql_build_array('UPDATE', array(
|
||||
'code' => (string) $this->code,
|
||||
'seed' => (int) $this->seed)) . '
|
||||
WHERE
|
||||
confirm_id = \'' . $db->sql_escape($this->confirm_id) . '\'
|
||||
AND session_id = \'' . $db->sql_escape($user->session_id) . '\'';
|
||||
$db->sql_query($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* New Question, if desired.
|
||||
*/
|
||||
function new_attempt()
|
||||
{
|
||||
global $db, $user;
|
||||
|
||||
$this->code = gen_rand_string_friendly(mt_rand(CAPTCHA_MIN_CHARS, CAPTCHA_MAX_CHARS));
|
||||
$this->seed = hexdec(substr(unique_id(), 4, 10));
|
||||
$this->solved = 0;
|
||||
// compute $seed % 0x7fffffff
|
||||
$this->seed -= 0x7fffffff * floor($this->seed / 0x7fffffff);
|
||||
|
||||
$sql = 'UPDATE ' . CONFIRM_TABLE . ' SET ' . $db->sql_build_array('UPDATE', array(
|
||||
'code' => (string) $this->code,
|
||||
'seed' => (int) $this->seed)) . '
|
||||
, attempts = attempts + 1
|
||||
WHERE
|
||||
confirm_id = \'' . $db->sql_escape($this->confirm_id) . '\'
|
||||
AND session_id = \'' . $db->sql_escape($user->session_id) . '\'';
|
||||
$db->sql_query($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up everything we need for painting&checking.
|
||||
*/
|
||||
function load_code()
|
||||
{
|
||||
global $db, $user;
|
||||
|
||||
$sql = 'SELECT code, seed, attempts
|
||||
FROM ' . CONFIRM_TABLE . "
|
||||
WHERE confirm_id = '" . $db->sql_escape($this->confirm_id) . "'
|
||||
AND session_id = '" . $db->sql_escape($user->session_id) . "'
|
||||
AND confirm_type = " . $this->type;
|
||||
$result = $db->sql_query($sql);
|
||||
$row = $db->sql_fetchrow($result);
|
||||
$db->sql_freeresult($result);
|
||||
|
||||
if ($row)
|
||||
{
|
||||
$this->code = $row['code'];
|
||||
$this->seed = $row['seed'];
|
||||
$this->attempts = $row['attempts'];
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function check_code()
|
||||
{
|
||||
return (strcasecmp($this->code, $this->confirm_code) === 0);
|
||||
}
|
||||
|
||||
function get_attempt_count()
|
||||
{
|
||||
return $this->attempts;
|
||||
}
|
||||
|
||||
function reset()
|
||||
{
|
||||
global $db, $user;
|
||||
|
||||
$sql = 'DELETE FROM ' . CONFIRM_TABLE . "
|
||||
WHERE session_id = '" . $db->sql_escape($user->session_id) . "'
|
||||
AND confirm_type = " . (int) $this->type;
|
||||
$db->sql_query($sql);
|
||||
|
||||
// we leave the class usable by generating a new question
|
||||
$this->generate_code();
|
||||
}
|
||||
|
||||
function is_solved()
|
||||
{
|
||||
global $request;
|
||||
|
||||
if ($request->variable('confirm_code', false) && $this->solved === 0)
|
||||
{
|
||||
$this->validate();
|
||||
}
|
||||
return (bool) $this->solved;
|
||||
}
|
||||
|
||||
/**
|
||||
* API function
|
||||
*/
|
||||
function has_config()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string the name of the service corresponding to the plugin
|
||||
*/
|
||||
function get_service_name()
|
||||
{
|
||||
return $this->service_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the plugin
|
||||
*
|
||||
* @param string $name
|
||||
*/
|
||||
public function set_name($name)
|
||||
{
|
||||
$this->service_name = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string the name of the class used to generate the captcha
|
||||
*/
|
||||
abstract function get_generator_class();
|
||||
}
|
||||
123
phpbb/captcha/plugins/gd.php
Normal file
123
phpbb/captcha/plugins/gd.php
Normal file
@@ -0,0 +1,123 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\captcha\plugins;
|
||||
|
||||
class gd extends captcha_abstract
|
||||
{
|
||||
var $captcha_vars = array(
|
||||
'captcha_gd_x_grid' => 'CAPTCHA_GD_X_GRID',
|
||||
'captcha_gd_y_grid' => 'CAPTCHA_GD_Y_GRID',
|
||||
'captcha_gd_foreground_noise' => 'CAPTCHA_GD_FOREGROUND_NOISE',
|
||||
// 'captcha_gd' => 'CAPTCHA_GD_PREVIEWED',
|
||||
'captcha_gd_wave' => 'CAPTCHA_GD_WAVE',
|
||||
'captcha_gd_3d_noise' => 'CAPTCHA_GD_3D_NOISE',
|
||||
'captcha_gd_fonts' => 'CAPTCHA_GD_FONTS',
|
||||
);
|
||||
|
||||
public function is_available()
|
||||
{
|
||||
return @extension_loaded('gd');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string the name of the class used to generate the captcha
|
||||
*/
|
||||
function get_generator_class()
|
||||
{
|
||||
return '\\phpbb\\captcha\\gd';
|
||||
}
|
||||
|
||||
/**
|
||||
* API function
|
||||
*/
|
||||
function has_config()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function get_name()
|
||||
{
|
||||
return 'CAPTCHA_GD';
|
||||
}
|
||||
|
||||
function acp_page($id, $module)
|
||||
{
|
||||
global $user, $template, $phpbb_log, $request;
|
||||
global $config;
|
||||
|
||||
$user->add_lang('acp/board');
|
||||
|
||||
$module->tpl_name = 'captcha_gd_acp';
|
||||
$module->page_title = 'ACP_VC_SETTINGS';
|
||||
$form_key = 'acp_captcha';
|
||||
add_form_key($form_key);
|
||||
|
||||
$submit = $request->variable('submit', '');
|
||||
|
||||
if ($submit && check_form_key($form_key))
|
||||
{
|
||||
$captcha_vars = array_keys($this->captcha_vars);
|
||||
foreach ($captcha_vars as $captcha_var)
|
||||
{
|
||||
$value = $request->variable($captcha_var, 0);
|
||||
if ($value >= 0)
|
||||
{
|
||||
$config->set($captcha_var, $value);
|
||||
}
|
||||
}
|
||||
|
||||
$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_CONFIG_VISUAL');
|
||||
trigger_error($user->lang['CONFIG_UPDATED'] . adm_back_link($module->u_action));
|
||||
}
|
||||
else if ($submit)
|
||||
{
|
||||
trigger_error($user->lang['FORM_INVALID'] . adm_back_link($module->u_action));
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach ($this->captcha_vars as $captcha_var => $template_var)
|
||||
{
|
||||
$var = (isset($_REQUEST[$captcha_var])) ? $request->variable($captcha_var, 0) : $config[$captcha_var];
|
||||
$template->assign_var($template_var, $var);
|
||||
}
|
||||
|
||||
$template->assign_vars(array(
|
||||
'CAPTCHA_PREVIEW' => $this->get_demo_template($id),
|
||||
'CAPTCHA_NAME' => $this->get_service_name(),
|
||||
'U_ACTION' => $module->u_action,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
function execute_demo()
|
||||
{
|
||||
global $config, $request;
|
||||
|
||||
$config_old = $config;
|
||||
|
||||
$config = new \phpbb\config\config(array());
|
||||
foreach ($config_old as $key => $value)
|
||||
{
|
||||
$config->set($key, $value);
|
||||
}
|
||||
|
||||
foreach ($this->captcha_vars as $captcha_var => $template_var)
|
||||
{
|
||||
$config->set($captcha_var, $request->variable($captcha_var, (int) $config[$captcha_var]));
|
||||
}
|
||||
parent::execute_demo();
|
||||
$config = $config_old;
|
||||
}
|
||||
|
||||
}
|
||||
42
phpbb/captcha/plugins/gd_wave.php
Normal file
42
phpbb/captcha/plugins/gd_wave.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\captcha\plugins;
|
||||
|
||||
class gd_wave extends captcha_abstract
|
||||
{
|
||||
public function is_available()
|
||||
{
|
||||
return @extension_loaded('gd');
|
||||
}
|
||||
|
||||
public function get_name()
|
||||
{
|
||||
return 'CAPTCHA_GD_3D';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string the name of the class used to generate the captcha
|
||||
*/
|
||||
function get_generator_class()
|
||||
{
|
||||
return '\\phpbb\\captcha\\gd_wave';
|
||||
}
|
||||
|
||||
function acp_page($id, $module)
|
||||
{
|
||||
global $user;
|
||||
|
||||
trigger_error($user->lang['CAPTCHA_NO_OPTIONS'] . adm_back_link($module->u_action));
|
||||
}
|
||||
}
|
||||
42
phpbb/captcha/plugins/nogd.php
Normal file
42
phpbb/captcha/plugins/nogd.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\captcha\plugins;
|
||||
|
||||
class nogd extends captcha_abstract
|
||||
{
|
||||
public function is_available()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function get_name()
|
||||
{
|
||||
return 'CAPTCHA_NO_GD';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string the name of the class used to generate the captcha
|
||||
*/
|
||||
function get_generator_class()
|
||||
{
|
||||
return '\\phpbb\\captcha\\non_gd';
|
||||
}
|
||||
|
||||
function acp_page($id, $module)
|
||||
{
|
||||
global $user;
|
||||
|
||||
trigger_error($user->lang['CAPTCHA_NO_OPTIONS'] . adm_back_link($module->u_action));
|
||||
}
|
||||
}
|
||||
1040
phpbb/captcha/plugins/qa.php
Normal file
1040
phpbb/captcha/plugins/qa.php
Normal file
File diff suppressed because it is too large
Load Diff
225
phpbb/captcha/plugins/recaptcha.php
Normal file
225
phpbb/captcha/plugins/recaptcha.php
Normal file
@@ -0,0 +1,225 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\captcha\plugins;
|
||||
|
||||
class recaptcha extends captcha_abstract
|
||||
{
|
||||
var $recaptcha_server = 'http://www.google.com/recaptcha/api';
|
||||
var $recaptcha_server_secure = 'https://www.google.com/recaptcha/api'; // class constants :(
|
||||
|
||||
var $response;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
global $request;
|
||||
$this->recaptcha_server = $request->is_secure() ? $this->recaptcha_server_secure : $this->recaptcha_server;
|
||||
}
|
||||
|
||||
function init($type)
|
||||
{
|
||||
global $user, $request;
|
||||
|
||||
$user->add_lang('captcha_recaptcha');
|
||||
parent::init($type);
|
||||
$this->response = $request->variable('g-recaptcha-response', '');
|
||||
}
|
||||
|
||||
public function is_available()
|
||||
{
|
||||
global $config, $user;
|
||||
$user->add_lang('captcha_recaptcha');
|
||||
return (isset($config['recaptcha_pubkey']) && !empty($config['recaptcha_pubkey']));
|
||||
}
|
||||
|
||||
/**
|
||||
* API function
|
||||
*/
|
||||
function has_config()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static public function get_name()
|
||||
{
|
||||
return 'CAPTCHA_RECAPTCHA';
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is implemented because required by the upper class, but is never used for reCaptcha.
|
||||
*/
|
||||
function get_generator_class()
|
||||
{
|
||||
throw new \Exception('No generator class given.');
|
||||
}
|
||||
|
||||
function acp_page($id, $module)
|
||||
{
|
||||
global $config, $template, $user, $phpbb_log, $request;
|
||||
|
||||
$captcha_vars = array(
|
||||
'recaptcha_pubkey' => 'RECAPTCHA_PUBKEY',
|
||||
'recaptcha_privkey' => 'RECAPTCHA_PRIVKEY',
|
||||
);
|
||||
|
||||
$module->tpl_name = 'captcha_recaptcha_acp';
|
||||
$module->page_title = 'ACP_VC_SETTINGS';
|
||||
$form_key = 'acp_captcha';
|
||||
add_form_key($form_key);
|
||||
|
||||
$submit = $request->variable('submit', '');
|
||||
|
||||
if ($submit && check_form_key($form_key))
|
||||
{
|
||||
$captcha_vars = array_keys($captcha_vars);
|
||||
foreach ($captcha_vars as $captcha_var)
|
||||
{
|
||||
$value = $request->variable($captcha_var, '');
|
||||
if ($value)
|
||||
{
|
||||
$config->set($captcha_var, $value);
|
||||
}
|
||||
}
|
||||
|
||||
$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_CONFIG_VISUAL');
|
||||
trigger_error($user->lang['CONFIG_UPDATED'] . adm_back_link($module->u_action));
|
||||
}
|
||||
else if ($submit)
|
||||
{
|
||||
trigger_error($user->lang['FORM_INVALID'] . adm_back_link($module->u_action));
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach ($captcha_vars as $captcha_var => $template_var)
|
||||
{
|
||||
$var = (isset($_REQUEST[$captcha_var])) ? $request->variable($captcha_var, '') : ((isset($config[$captcha_var])) ? $config[$captcha_var] : '');
|
||||
$template->assign_var($template_var, $var);
|
||||
}
|
||||
|
||||
$template->assign_vars(array(
|
||||
'CAPTCHA_PREVIEW' => $this->get_demo_template($id),
|
||||
'CAPTCHA_NAME' => $this->get_service_name(),
|
||||
'U_ACTION' => $module->u_action,
|
||||
));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// not needed
|
||||
function execute_demo()
|
||||
{
|
||||
}
|
||||
|
||||
// not needed
|
||||
function execute()
|
||||
{
|
||||
}
|
||||
|
||||
function get_template()
|
||||
{
|
||||
global $config, $user, $template, $phpbb_root_path, $phpEx;
|
||||
|
||||
if ($this->is_solved())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
$contact_link = phpbb_get_board_contact_link($config, $phpbb_root_path, $phpEx);
|
||||
$explain = $user->lang(($this->type != CONFIRM_POST) ? 'CONFIRM_EXPLAIN' : 'POST_CONFIRM_EXPLAIN', '<a href="' . $contact_link . '">', '</a>');
|
||||
|
||||
$template->assign_vars(array(
|
||||
'RECAPTCHA_SERVER' => $this->recaptcha_server,
|
||||
'RECAPTCHA_PUBKEY' => isset($config['recaptcha_pubkey']) ? $config['recaptcha_pubkey'] : '',
|
||||
'S_RECAPTCHA_AVAILABLE' => self::is_available(),
|
||||
'S_CONFIRM_CODE' => true,
|
||||
'S_TYPE' => $this->type,
|
||||
'L_CONFIRM_EXPLAIN' => $explain,
|
||||
));
|
||||
|
||||
return 'captcha_recaptcha.html';
|
||||
}
|
||||
}
|
||||
|
||||
function get_demo_template($id)
|
||||
{
|
||||
return $this->get_template();
|
||||
}
|
||||
|
||||
function get_hidden_fields()
|
||||
{
|
||||
$hidden_fields = array();
|
||||
|
||||
// this is required for posting.php - otherwise we would forget about the captcha being already solved
|
||||
if ($this->solved)
|
||||
{
|
||||
$hidden_fields['confirm_code'] = $this->code;
|
||||
}
|
||||
$hidden_fields['confirm_id'] = $this->confirm_id;
|
||||
return $hidden_fields;
|
||||
}
|
||||
|
||||
function uninstall()
|
||||
{
|
||||
$this->garbage_collect(0);
|
||||
}
|
||||
|
||||
function install()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
function validate()
|
||||
{
|
||||
if (!parent::validate())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return $this->recaptcha_check_answer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls an HTTP POST function to verify if the user's guess was correct
|
||||
*
|
||||
* @return bool|string Returns false on success or error string on failure.
|
||||
*/
|
||||
function recaptcha_check_answer()
|
||||
{
|
||||
global $config, $user;
|
||||
|
||||
//discard spam submissions
|
||||
if ($this->response == null || strlen($this->response) == 0)
|
||||
{
|
||||
return $user->lang['RECAPTCHA_INCORRECT'];
|
||||
}
|
||||
|
||||
$recaptcha = new \ReCaptcha\ReCaptcha($config['recaptcha_privkey']);
|
||||
$result = $recaptcha->verify($this->response, $user->ip);
|
||||
|
||||
if ($result->isSuccess())
|
||||
{
|
||||
$this->solved = true;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return $user->lang['RECAPTCHA_INCORRECT'];
|
||||
}
|
||||
}
|
||||
}
|
||||
164
phpbb/class_loader.php
Normal file
164
phpbb/class_loader.php
Normal file
@@ -0,0 +1,164 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb;
|
||||
|
||||
/**
|
||||
* The class loader resolves class names to file system paths and loads them if
|
||||
* necessary.
|
||||
*
|
||||
* Classes have to be of the form phpbb_(dir_)*(classpart_)*, so directory names
|
||||
* must never contain underscores. Example: phpbb_dir_subdir_class_name is a
|
||||
* valid class name, while phpbb_dir_sub_dir_class_name is not.
|
||||
*
|
||||
* If every part of the class name is a directory, the last directory name is
|
||||
* also used as the filename, e.g. phpbb_dir would resolve to dir/dir.php.
|
||||
*/
|
||||
class class_loader
|
||||
{
|
||||
private $namespace;
|
||||
private $path;
|
||||
private $php_ext;
|
||||
private $cache;
|
||||
|
||||
/**
|
||||
* A map of looked up class names to paths relative to $this->path.
|
||||
* This map is stored in cache and looked up if the cache is available.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $cached_paths = array();
|
||||
|
||||
/**
|
||||
* Creates a new \phpbb\class_loader, which loads files with the given
|
||||
* file extension from the given path.
|
||||
*
|
||||
* @param string $namespace Required namespace for files to be loaded
|
||||
* @param string $path Directory to load files from
|
||||
* @param string $php_ext The file extension for PHP files
|
||||
* @param \phpbb\cache\driver\driver_interface $cache An implementation of the phpBB cache interface.
|
||||
*/
|
||||
public function __construct($namespace, $path, $php_ext = 'php', \phpbb\cache\driver\driver_interface $cache = null)
|
||||
{
|
||||
if ($namespace[0] !== '\\')
|
||||
{
|
||||
$namespace = '\\' . $namespace;
|
||||
}
|
||||
|
||||
$this->namespace = $namespace;
|
||||
$this->path = $path;
|
||||
$this->php_ext = $php_ext;
|
||||
|
||||
$this->set_cache($cache);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide the class loader with a cache to store paths. If set to null, the
|
||||
* the class loader will resolve paths by checking for the existance of every
|
||||
* directory in the class name every time.
|
||||
*
|
||||
* @param \phpbb\cache\driver\driver_interface $cache An implementation of the phpBB cache interface.
|
||||
*/
|
||||
public function set_cache(\phpbb\cache\driver\driver_interface $cache = null)
|
||||
{
|
||||
if ($cache)
|
||||
{
|
||||
$this->cached_paths = $cache->get('class_loader_' . str_replace('\\', '__', $this->namespace));
|
||||
|
||||
if ($this->cached_paths === false)
|
||||
{
|
||||
$this->cached_paths = array();
|
||||
}
|
||||
}
|
||||
|
||||
$this->cache = $cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the class loader as an autoloader using SPL.
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
spl_autoload_register(array($this, 'load_class'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the class loader from the SPL autoloader stack.
|
||||
*/
|
||||
public function unregister()
|
||||
{
|
||||
spl_autoload_unregister(array($this, 'load_class'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a phpBB class name to a relative path which can be included.
|
||||
*
|
||||
* @param string $class The class name to resolve, must be in the
|
||||
* namespace the loader was constructed with.
|
||||
* Has to begin with \
|
||||
* @return string|bool A relative path to the file containing the
|
||||
* class or false if looking it up failed.
|
||||
*/
|
||||
public function resolve_path($class)
|
||||
{
|
||||
if (isset($this->cached_paths[$class]))
|
||||
{
|
||||
return $this->path . $this->cached_paths[$class] . '.' . $this->php_ext;
|
||||
}
|
||||
|
||||
if (!preg_match('/^' . preg_quote($this->namespace, '/') . '[a-zA-Z0-9_\\\\]+$/', $class))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$relative_path = str_replace('\\', '/', substr($class, strlen($this->namespace)));
|
||||
|
||||
if (!file_exists($this->path . $relative_path . '.' . $this->php_ext))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->cache)
|
||||
{
|
||||
$this->cached_paths[$class] = $relative_path;
|
||||
$this->cache->put('class_loader_' . str_replace('\\', '__', $this->namespace), $this->cached_paths);
|
||||
}
|
||||
|
||||
return $this->path . $relative_path . '.' . $this->php_ext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a class name to a path and then includes it.
|
||||
*
|
||||
* @param string $class The class name which is being loaded.
|
||||
*/
|
||||
public function load_class($class)
|
||||
{
|
||||
// In general $class is not supposed to contain a leading backslash,
|
||||
// but sometimes it does. See tickets PHP-50731 and HHVM-1840.
|
||||
if ($class[0] !== '\\')
|
||||
{
|
||||
$class = '\\' . $class;
|
||||
}
|
||||
|
||||
if (substr($class, 0, strlen($this->namespace)) === $this->namespace)
|
||||
{
|
||||
$path = $this->resolve_path($class);
|
||||
|
||||
if ($path)
|
||||
{
|
||||
require $path;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
32
phpbb/composer.json
Normal file
32
phpbb/composer.json
Normal file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"name": "phpbb/phpbb-core",
|
||||
"description": "Collection of core phpBB libraries",
|
||||
"type": "library",
|
||||
"keywords": ["phpbb", "forum"],
|
||||
"homepage": "https://www.phpbb.com",
|
||||
"license": "GPL-2.0",
|
||||
"authors": [
|
||||
{
|
||||
"name": "phpBB Limited",
|
||||
"email": "operations@phpbb.com",
|
||||
"homepage": "https://www.phpbb.com/go/authors"
|
||||
}
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://tracker.phpbb.com",
|
||||
"forum": "https://www.phpbb.com/community/",
|
||||
"wiki": "https://wiki.phpbb.com",
|
||||
"irc": "irc://irc.freenode.org/phpbb"
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [""]
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.4"
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.3.x-dev"
|
||||
}
|
||||
}
|
||||
}
|
||||
167
phpbb/config/config.php
Normal file
167
phpbb/config/config.php
Normal file
@@ -0,0 +1,167 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\config;
|
||||
|
||||
/**
|
||||
* Configuration container class
|
||||
*/
|
||||
class config implements \ArrayAccess, \IteratorAggregate, \Countable
|
||||
{
|
||||
/**
|
||||
* The configuration data
|
||||
* @var array(string => string)
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* Creates a configuration container with a default set of values
|
||||
*
|
||||
* @param array(string => string) $config The configuration data.
|
||||
*/
|
||||
public function __construct(array $config)
|
||||
{
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves an ArrayIterator over the configuration values.
|
||||
*
|
||||
* @return \ArrayIterator An iterator over all config data
|
||||
*/
|
||||
public function getIterator()
|
||||
{
|
||||
return new \ArrayIterator($this->config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the specified config value exists.
|
||||
*
|
||||
* @param string $key The configuration option's name.
|
||||
* @return bool Whether the configuration option exists.
|
||||
*/
|
||||
public function offsetExists($key)
|
||||
{
|
||||
return isset($this->config[$key]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a configuration value.
|
||||
*
|
||||
* @param string $key The configuration option's name.
|
||||
* @return string The configuration value
|
||||
*/
|
||||
public function offsetGet($key)
|
||||
{
|
||||
return (isset($this->config[$key])) ? $this->config[$key] : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Temporarily overwrites the value of a configuration variable.
|
||||
*
|
||||
* The configuration change will not persist. It will be lost
|
||||
* after the request.
|
||||
*
|
||||
* @param string $key The configuration option's name.
|
||||
* @param string $value The temporary value.
|
||||
*/
|
||||
public function offsetSet($key, $value)
|
||||
{
|
||||
$this->config[$key] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when deleting a configuration value directly, triggers an error.
|
||||
*
|
||||
* @param string $key The configuration option's name.
|
||||
*/
|
||||
public function offsetUnset($key)
|
||||
{
|
||||
trigger_error('Config values have to be deleted explicitly with the \phpbb\config\config::delete($key) method.', E_USER_ERROR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the number of configuration options currently set.
|
||||
*
|
||||
* @return int Number of config options
|
||||
*/
|
||||
public function count()
|
||||
{
|
||||
return count($this->config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a configuration option
|
||||
*
|
||||
* @param String $key The configuration option's name
|
||||
* @param bool $use_cache Whether this variable should be cached or if it
|
||||
* changes too frequently to be efficiently cached
|
||||
* @return null
|
||||
*/
|
||||
public function delete($key, $use_cache = true)
|
||||
{
|
||||
unset($this->config[$key]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a configuration option's value
|
||||
*
|
||||
* @param string $key The configuration option's name
|
||||
* @param string $value New configuration value
|
||||
* @param bool $use_cache Whether this variable should be cached or if it
|
||||
* changes too frequently to be efficiently cached.
|
||||
*/
|
||||
public function set($key, $value, $use_cache = true)
|
||||
{
|
||||
$this->config[$key] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a configuration option's value only if the old_value matches the
|
||||
* current configuration value or the configuration value does not exist yet.
|
||||
*
|
||||
* @param string $key The configuration option's name
|
||||
* @param string $old_value Current configuration value
|
||||
* @param string $new_value New configuration value
|
||||
* @param bool $use_cache Whether this variable should be cached or if it
|
||||
* changes too frequently to be efficiently cached.
|
||||
* @return bool True if the value was changed, false otherwise.
|
||||
*/
|
||||
public function set_atomic($key, $old_value, $new_value, $use_cache = true)
|
||||
{
|
||||
if (!isset($this->config[$key]) || $this->config[$key] == $old_value)
|
||||
{
|
||||
$this->config[$key] = $new_value;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments an integer configuration value.
|
||||
*
|
||||
* @param string $key The configuration option's name
|
||||
* @param int $increment Amount to increment by
|
||||
* @param bool $use_cache Whether this variable should be cached or if it
|
||||
* changes too frequently to be efficiently cached.
|
||||
*/
|
||||
function increment($key, $increment, $use_cache = true)
|
||||
{
|
||||
if (!isset($this->config[$key]))
|
||||
{
|
||||
$this->config[$key] = 0;
|
||||
}
|
||||
|
||||
$this->config[$key] += $increment;
|
||||
}
|
||||
}
|
||||
204
phpbb/config/db.php
Normal file
204
phpbb/config/db.php
Normal file
@@ -0,0 +1,204 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\config;
|
||||
|
||||
/**
|
||||
* Configuration container class
|
||||
*/
|
||||
class db extends \phpbb\config\config
|
||||
{
|
||||
/**
|
||||
* Cache instance
|
||||
* @var \phpbb\cache\driver\driver_interface
|
||||
*/
|
||||
protected $cache;
|
||||
|
||||
/**
|
||||
* Database connection
|
||||
* @var \phpbb\db\driver\driver_interface
|
||||
*/
|
||||
protected $db;
|
||||
|
||||
/**
|
||||
* Name of the database table used for configuration.
|
||||
* @var string
|
||||
*/
|
||||
protected $table;
|
||||
|
||||
/**
|
||||
* Creates a configuration container with a default set of values
|
||||
*
|
||||
* @param \phpbb\db\driver\driver_interface $db Database connection
|
||||
* @param \phpbb\cache\driver\driver_interface $cache Cache instance
|
||||
* @param string $table Configuration table name
|
||||
*/
|
||||
public function __construct(\phpbb\db\driver\driver_interface $db, \phpbb\cache\driver\driver_interface $cache, $table)
|
||||
{
|
||||
$this->db = $db;
|
||||
$this->cache = $cache;
|
||||
$this->table = $table;
|
||||
|
||||
if (($config = $cache->get('config')) !== false)
|
||||
{
|
||||
$sql = 'SELECT config_name, config_value
|
||||
FROM ' . $this->table . '
|
||||
WHERE is_dynamic = 1';
|
||||
$result = $this->db->sql_query($sql);
|
||||
|
||||
while ($row = $this->db->sql_fetchrow($result))
|
||||
{
|
||||
$config[$row['config_name']] = $row['config_value'];
|
||||
}
|
||||
$this->db->sql_freeresult($result);
|
||||
}
|
||||
else
|
||||
{
|
||||
$config = $cached_config = array();
|
||||
|
||||
$sql = 'SELECT config_name, config_value, is_dynamic
|
||||
FROM ' . $this->table;
|
||||
$result = $this->db->sql_query($sql);
|
||||
|
||||
while ($row = $this->db->sql_fetchrow($result))
|
||||
{
|
||||
if (!$row['is_dynamic'])
|
||||
{
|
||||
$cached_config[$row['config_name']] = $row['config_value'];
|
||||
}
|
||||
|
||||
$config[$row['config_name']] = $row['config_value'];
|
||||
}
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
$cache->put('config', $cached_config);
|
||||
}
|
||||
|
||||
parent::__construct($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a configuration option
|
||||
*
|
||||
* @param String $key The configuration option's name
|
||||
* @param bool $use_cache Whether this variable should be cached or if it
|
||||
* changes too frequently to be efficiently cached
|
||||
* @return null
|
||||
*/
|
||||
public function delete($key, $use_cache = true)
|
||||
{
|
||||
$sql = 'DELETE FROM ' . $this->table . "
|
||||
WHERE config_name = '" . $this->db->sql_escape($key) . "'";
|
||||
$this->db->sql_query($sql);
|
||||
|
||||
unset($this->config[$key]);
|
||||
|
||||
if ($use_cache)
|
||||
{
|
||||
$this->cache->destroy('config');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a configuration option's value
|
||||
*
|
||||
* @param string $key The configuration option's name
|
||||
* @param string $value New configuration value
|
||||
* @param bool $use_cache Whether this variable should be cached or if it
|
||||
* changes too frequently to be efficiently cached.
|
||||
*/
|
||||
public function set($key, $value, $use_cache = true)
|
||||
{
|
||||
$this->set_atomic($key, false, $value, $use_cache);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a configuration option's value only if the old_value matches the
|
||||
* current configuration value or the configuration value does not exist yet.
|
||||
*
|
||||
* @param string $key The configuration option's name
|
||||
* @param mixed $old_value Current configuration value or false to ignore
|
||||
* the old value
|
||||
* @param string $new_value New configuration value
|
||||
* @param bool $use_cache Whether this variable should be cached or if it
|
||||
* changes too frequently to be efficiently cached
|
||||
* @return bool True if the value was changed, false otherwise
|
||||
*/
|
||||
public function set_atomic($key, $old_value, $new_value, $use_cache = true)
|
||||
{
|
||||
$sql = 'UPDATE ' . $this->table . "
|
||||
SET config_value = '" . $this->db->sql_escape($new_value) . "'
|
||||
WHERE config_name = '" . $this->db->sql_escape($key) . "'";
|
||||
|
||||
if ($old_value !== false)
|
||||
{
|
||||
$sql .= " AND config_value = '" . $this->db->sql_escape($old_value) . "'";
|
||||
}
|
||||
|
||||
$this->db->sql_query($sql);
|
||||
|
||||
if (!$this->db->sql_affectedrows() && isset($this->config[$key]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isset($this->config[$key]))
|
||||
{
|
||||
$sql = 'INSERT INTO ' . $this->table . ' ' . $this->db->sql_build_array('INSERT', array(
|
||||
'config_name' => $key,
|
||||
'config_value' => $new_value,
|
||||
'is_dynamic' => ($use_cache) ? 0 : 1));
|
||||
$this->db->sql_query($sql);
|
||||
}
|
||||
|
||||
if ($use_cache)
|
||||
{
|
||||
$this->cache->destroy('config');
|
||||
}
|
||||
|
||||
$this->config[$key] = $new_value;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments an integer config value directly in the database.
|
||||
*
|
||||
* Using this method instead of setting the new value directly avoids race
|
||||
* conditions and unlike set_atomic it cannot fail.
|
||||
*
|
||||
* @param string $key The configuration option's name
|
||||
* @param int $increment Amount to increment by
|
||||
* @param bool $use_cache Whether this variable should be cached or if it
|
||||
* changes too frequently to be efficiently cached.
|
||||
*/
|
||||
function increment($key, $increment, $use_cache = true)
|
||||
{
|
||||
if (!isset($this->config[$key]))
|
||||
{
|
||||
$this->set($key, '0', $use_cache);
|
||||
}
|
||||
|
||||
$sql_update = $this->db->cast_expr_to_string($this->db->cast_expr_to_bigint('config_value') . ' + ' . (int) $increment);
|
||||
|
||||
$this->db->sql_query('UPDATE ' . $this->table . '
|
||||
SET config_value = ' . $sql_update . "
|
||||
WHERE config_name = '" . $this->db->sql_escape($key) . "'");
|
||||
|
||||
if ($use_cache)
|
||||
{
|
||||
$this->cache->destroy('config');
|
||||
}
|
||||
|
||||
$this->config[$key] += $increment;
|
||||
}
|
||||
}
|
||||
159
phpbb/config/db_text.php
Normal file
159
phpbb/config/db_text.php
Normal file
@@ -0,0 +1,159 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\config;
|
||||
|
||||
/**
|
||||
* Manages configuration options with an arbitrary length value stored in a TEXT
|
||||
* column. In constrast to class \phpbb\config\db, values are never cached and
|
||||
* prefetched, but every get operation sends a query to the database.
|
||||
*/
|
||||
class db_text
|
||||
{
|
||||
/**
|
||||
* Database connection
|
||||
* @var \phpbb\db\driver\driver_interface
|
||||
*/
|
||||
protected $db;
|
||||
|
||||
/**
|
||||
* Name of the database table used.
|
||||
* @var string
|
||||
*/
|
||||
protected $table;
|
||||
|
||||
/**
|
||||
* @param \phpbb\db\driver\driver_interface $db Database connection
|
||||
* @param string $table Table name
|
||||
*/
|
||||
public function __construct(\phpbb\db\driver\driver_interface $db, $table)
|
||||
{
|
||||
$this->db = $db;
|
||||
$this->table = $this->db->sql_escape($table);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the configuration option with the name $key to $value.
|
||||
*
|
||||
* @param string $key The configuration option's name
|
||||
* @param string $value New configuration value
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
public function set($key, $value)
|
||||
{
|
||||
$this->set_array(array($key => $value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the configuration value for the name $key.
|
||||
*
|
||||
* @param string $key The configuration option's name
|
||||
*
|
||||
* @return string|null String result on success
|
||||
* null if there is no such option
|
||||
*/
|
||||
public function get($key)
|
||||
{
|
||||
$map = $this->get_array(array($key));
|
||||
|
||||
return isset($map[$key]) ? $map[$key] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the configuration option with the name $key.
|
||||
*
|
||||
* @param string $key The configuration option's name
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
public function delete($key)
|
||||
{
|
||||
$this->delete_array(array($key));
|
||||
}
|
||||
|
||||
/**
|
||||
* Mass set configuration options: Receives an associative array,
|
||||
* treats array keys as configuration option names and associated
|
||||
* array values as their configuration option values.
|
||||
*
|
||||
* @param array $map Map from configuration names to values
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
public function set_array(array $map)
|
||||
{
|
||||
$this->db->sql_transaction('begin');
|
||||
|
||||
foreach ($map as $key => $value)
|
||||
{
|
||||
$sql = 'UPDATE ' . $this->table . "
|
||||
SET config_value = '" . $this->db->sql_escape($value) . "'
|
||||
WHERE config_name = '" . $this->db->sql_escape($key) . "'";
|
||||
$this->db->sql_query($sql);
|
||||
|
||||
if (!$this->db->sql_affectedrows())
|
||||
{
|
||||
$sql = 'INSERT INTO ' . $this->table . ' ' . $this->db->sql_build_array('INSERT', array(
|
||||
'config_name' => (string) $key,
|
||||
'config_value' => (string) $value,
|
||||
));
|
||||
$this->db->sql_query($sql);
|
||||
}
|
||||
}
|
||||
|
||||
$this->db->sql_transaction('commit');
|
||||
}
|
||||
|
||||
/**
|
||||
* Mass get configuration options: Receives a set of configuration
|
||||
* option names and returns the result as a key => value map where
|
||||
* array keys are configuration option names and array values are
|
||||
* associated config option values.
|
||||
*
|
||||
* @param array $keys Set of configuration option names
|
||||
*
|
||||
* @return array Map from configuration names to values
|
||||
*/
|
||||
public function get_array(array $keys)
|
||||
{
|
||||
$sql = 'SELECT *
|
||||
FROM ' . $this->table . '
|
||||
WHERE ' . $this->db->sql_in_set('config_name', $keys, false, true);
|
||||
$result = $this->db->sql_query($sql);
|
||||
|
||||
$map = array();
|
||||
while ($row = $this->db->sql_fetchrow($result))
|
||||
{
|
||||
$map[$row['config_name']] = $row['config_value'];
|
||||
}
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
return $map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mass delete configuration options.
|
||||
*
|
||||
* @param array $keys Set of configuration option names
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
public function delete_array(array $keys)
|
||||
{
|
||||
$sql = 'DELETE
|
||||
FROM ' . $this->table . '
|
||||
WHERE ' . $this->db->sql_in_set('config_name', $keys, false, true);
|
||||
$this->db->sql_query($sql);
|
||||
}
|
||||
}
|
||||
160
phpbb/config_php_file.php
Normal file
160
phpbb/config_php_file.php
Normal file
@@ -0,0 +1,160 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb;
|
||||
|
||||
class config_php_file
|
||||
{
|
||||
/** @var string phpBB Root Path */
|
||||
protected $phpbb_root_path;
|
||||
|
||||
/** @var string php file extension */
|
||||
protected $php_ext;
|
||||
|
||||
/**
|
||||
* Indicates whether the php config file has been loaded.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $config_loaded = false;
|
||||
|
||||
/**
|
||||
* The content of the php config file
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $config_data = array();
|
||||
|
||||
/**
|
||||
* The path to the config file. (Default: $phpbb_root_path . 'config.' . $php_ext)
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $config_file;
|
||||
|
||||
private $defined_vars;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $phpbb_root_path phpBB Root Path
|
||||
* @param string $php_ext php file extension
|
||||
*/
|
||||
function __construct($phpbb_root_path, $php_ext)
|
||||
{
|
||||
$this->phpbb_root_path = $phpbb_root_path;
|
||||
$this->php_ext = $php_ext;
|
||||
$this->config_file = $this->phpbb_root_path . 'config.' . $this->php_ext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the path to the config file.
|
||||
*
|
||||
* @param string $config_file
|
||||
*/
|
||||
public function set_config_file($config_file)
|
||||
{
|
||||
$this->config_file = $config_file;
|
||||
$this->config_loaded = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an associative array containing the variables defined by the config file.
|
||||
*
|
||||
* @return array Return the content of the config file or an empty array if the file does not exists.
|
||||
*/
|
||||
public function get_all()
|
||||
{
|
||||
$this->load_config_file();
|
||||
|
||||
return $this->config_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the value of a variable defined into the config.php file or null if the variable does not exist.
|
||||
*
|
||||
* @param string $variable The name of the variable
|
||||
* @return mixed Value of the variable or null if the variable is not defined.
|
||||
*/
|
||||
public function get($variable)
|
||||
{
|
||||
$this->load_config_file();
|
||||
|
||||
return isset($this->config_data[$variable]) ? $this->config_data[$variable] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the config file and store the information.
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
protected function load_config_file()
|
||||
{
|
||||
if (!$this->config_loaded && file_exists($this->config_file))
|
||||
{
|
||||
$this->defined_vars = get_defined_vars();
|
||||
|
||||
require($this->config_file);
|
||||
$this->config_data = array_diff_key(get_defined_vars(), $this->defined_vars);
|
||||
|
||||
$this->config_loaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert either 3.0 dbms or 3.1 db driver class name to 3.1 db driver class name.
|
||||
*
|
||||
* If $dbms is a valid 3.1 db driver class name, returns it unchanged.
|
||||
* Otherwise prepends phpbb\db\driver\ to the dbms to convert a 3.0 dbms
|
||||
* to 3.1 db driver class name.
|
||||
*
|
||||
* @param string $dbms dbms parameter
|
||||
* @return string driver class
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function convert_30_dbms_to_31($dbms)
|
||||
{
|
||||
// Note: this check is done first because mysqli extension
|
||||
// supplies a mysqli class, and class_exists($dbms) would return
|
||||
// true for mysqli class.
|
||||
// However, per the docblock any valid 3.1 driver name should be
|
||||
// recognized by this function, and have priority over 3.0 dbms.
|
||||
if (strpos($dbms, 'phpbb\db\driver') === false && class_exists('phpbb\db\driver\\' . $dbms))
|
||||
{
|
||||
return 'phpbb\db\driver\\' . $dbms;
|
||||
}
|
||||
|
||||
if (class_exists($dbms))
|
||||
{
|
||||
// Additionally we could check that $dbms extends phpbb\db\driver\driver.
|
||||
// http://php.net/manual/en/class.reflectionclass.php
|
||||
// Beware of possible performance issues:
|
||||
// http://stackoverflow.com/questions/294582/php-5-reflection-api-performance
|
||||
// We could check for interface implementation in all paths or
|
||||
// only when we do not prepend phpbb\db\driver\.
|
||||
|
||||
/*
|
||||
$reflection = new \ReflectionClass($dbms);
|
||||
|
||||
if ($reflection->isSubclassOf('phpbb\db\driver\driver'))
|
||||
{
|
||||
return $dbms;
|
||||
}
|
||||
*/
|
||||
|
||||
return $dbms;
|
||||
}
|
||||
|
||||
throw new \RuntimeException("You have specified an invalid dbms driver: $dbms");
|
||||
}
|
||||
}
|
||||
153
phpbb/console/application.php
Normal file
153
phpbb/console/application.php
Normal file
@@ -0,0 +1,153 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\console;
|
||||
|
||||
use Symfony\Component\Console\Input\InputDefinition;
|
||||
use Symfony\Component\Console\Shell;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class application extends \Symfony\Component\Console\Application
|
||||
{
|
||||
/**
|
||||
* @var bool Indicates whether or not we are in a shell
|
||||
*/
|
||||
protected $in_shell = false;
|
||||
|
||||
/**
|
||||
* @var \phpbb\language\language User object
|
||||
*/
|
||||
protected $language;
|
||||
|
||||
/**
|
||||
* @param string $name The name of the application
|
||||
* @param string $version The version of the application
|
||||
* @param \phpbb\language\language $language The user which runs the application (used for translation)
|
||||
*/
|
||||
public function __construct($name, $version, \phpbb\language\language $language)
|
||||
{
|
||||
$this->language = $language;
|
||||
|
||||
parent::__construct($name, $version);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getDefaultInputDefinition()
|
||||
{
|
||||
$input_definition = parent::getDefaultInputDefinition();
|
||||
|
||||
$this->register_global_options($input_definition);
|
||||
|
||||
return $input_definition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the help message.
|
||||
*
|
||||
* It's a hack of the default help message to display the --shell
|
||||
* option only for the application and not for all the commands.
|
||||
*
|
||||
* @return string A help message.
|
||||
*/
|
||||
public function getHelp()
|
||||
{
|
||||
// If we are already in a shell
|
||||
// we do not want to have the --shell option available
|
||||
if ($this->in_shell)
|
||||
{
|
||||
return parent::getHelp();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$definition = $this->getDefinition();
|
||||
$definition->addOption(new InputOption(
|
||||
'--shell',
|
||||
'-s',
|
||||
InputOption::VALUE_NONE,
|
||||
$this->language->lang('CLI_DESCRIPTION_OPTION_SHELL')
|
||||
));
|
||||
}
|
||||
catch (\LogicException $e)
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
return parent::getHelp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a set of commands from the container
|
||||
*
|
||||
* @param \phpbb\di\service_collection $command_collection The console service collection
|
||||
*/
|
||||
public function register_container_commands(\phpbb\di\service_collection $command_collection)
|
||||
{
|
||||
foreach ($command_collection as $service_command)
|
||||
{
|
||||
$this->add($service_command);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function doRun(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
// Run a shell if the --shell (or -s) option is set and if no command name is specified
|
||||
// Also, we do not want to have the --shell option available if we are already in a shell
|
||||
if (!$this->in_shell && $this->getCommandName($input) === null && $input->hasParameterOption(array('--shell', '-s')))
|
||||
{
|
||||
$shell = new Shell($this);
|
||||
$this->in_shell = true;
|
||||
$shell->run();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return parent::doRun($input, $output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register global options
|
||||
*
|
||||
* @param InputDefinition $definition An InputDefinition instance
|
||||
*/
|
||||
protected function register_global_options(InputDefinition $definition)
|
||||
{
|
||||
try
|
||||
{
|
||||
$definition->addOption(new InputOption(
|
||||
'safe-mode',
|
||||
null,
|
||||
InputOption::VALUE_NONE,
|
||||
$this->language->lang('CLI_DESCRIPTION_OPTION_SAFE_MODE')
|
||||
));
|
||||
|
||||
$definition->addOption(new InputOption(
|
||||
'env',
|
||||
'e',
|
||||
InputOption::VALUE_REQUIRED,
|
||||
$this->language->lang('CLI_DESCRIPTION_OPTION_ENV')
|
||||
));
|
||||
}
|
||||
catch (\LogicException $e)
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
91
phpbb/console/command/cache/purge.php
vendored
Normal file
91
phpbb/console/command/cache/purge.php
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
namespace phpbb\console\command\cache;
|
||||
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
class purge extends \phpbb\console\command\command
|
||||
{
|
||||
/** @var \phpbb\cache\driver\driver_interface */
|
||||
protected $cache;
|
||||
|
||||
/** @var \phpbb\db\driver\driver_interface */
|
||||
protected $db;
|
||||
|
||||
/** @var \phpbb\auth\auth */
|
||||
protected $auth;
|
||||
|
||||
/** @var \phpbb\log\log_interface */
|
||||
protected $log;
|
||||
|
||||
/** @var \phpbb\config\config */
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \phpbb\user $user User instance
|
||||
* @param \phpbb\cache\driver\driver_interface $cache Cache instance
|
||||
* @param \phpbb\db\driver\driver_interface $db Database connection
|
||||
* @param \phpbb\auth\auth $auth Auth instance
|
||||
* @param \phpbb\log\log_interface $log Logger instance
|
||||
* @param \phpbb\config\config $config Config instance
|
||||
*/
|
||||
public function __construct(\phpbb\user $user, \phpbb\cache\driver\driver_interface $cache, \phpbb\db\driver\driver_interface $db, \phpbb\auth\auth $auth, \phpbb\log\log_interface $log, \phpbb\config\config $config)
|
||||
{
|
||||
$this->cache = $cache;
|
||||
$this->db = $db;
|
||||
$this->auth = $auth;
|
||||
$this->log = $log;
|
||||
$this->config = $config;
|
||||
parent::__construct($user);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('cache:purge')
|
||||
->setDescription($this->user->lang('PURGE_CACHE'))
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the command cache:purge.
|
||||
*
|
||||
* Purge the cache (including permissions) and increment the asset_version number
|
||||
*
|
||||
* @param InputInterface $input An InputInterface instance
|
||||
* @param OutputInterface $output An OutputInterface instance
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$this->config->increment('assets_version', 1);
|
||||
$this->cache->purge();
|
||||
|
||||
// Clear permissions
|
||||
$this->auth->acl_clear_prefetch();
|
||||
phpbb_cache_moderators($this->db, $this->cache, $this->auth);
|
||||
|
||||
$this->log->add('admin', ANONYMOUS, '', 'LOG_PURGE_CACHE', time(), array());
|
||||
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$io->success($this->user->lang('PURGE_CACHE_SUCCESS'));
|
||||
}
|
||||
}
|
||||
76
phpbb/console/command/command.php
Normal file
76
phpbb/console/command/command.php
Normal file
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\console\command;
|
||||
|
||||
use Symfony\Component\Console\Helper\ProgressBar;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
abstract class command extends \Symfony\Component\Console\Command\Command
|
||||
{
|
||||
/** @var \phpbb\user */
|
||||
protected $user;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \phpbb\user $user User instance (mostly for translation)
|
||||
*/
|
||||
public function __construct(\phpbb\user $user)
|
||||
{
|
||||
$this->user = $user;
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a styled progress bar
|
||||
*
|
||||
* @param int $max Max value for the progress bar
|
||||
* @param SymfonyStyle $io Symfony style output decorator
|
||||
* @param OutputInterface $output The output stream, used to print messages
|
||||
* @param bool $message Should we display message output under the progress bar?
|
||||
* @return ProgressBar
|
||||
*/
|
||||
public function create_progress_bar($max, SymfonyStyle $io, OutputInterface $output, $message = false)
|
||||
{
|
||||
$progress = $io->createProgressBar($max);
|
||||
if ($output->getVerbosity() === OutputInterface::VERBOSITY_VERBOSE)
|
||||
{
|
||||
$progress->setFormat('<info>[%percent:3s%%]</info> %message%');
|
||||
$progress->setOverwrite(false);
|
||||
}
|
||||
else if ($output->getVerbosity() >= OutputInterface::VERBOSITY_VERY_VERBOSE)
|
||||
{
|
||||
$progress->setFormat('<info>[%current:s%/%max:s%]</info><comment>[%elapsed%/%estimated%][%memory%]</comment> %message%');
|
||||
$progress->setOverwrite(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
$io->newLine(2);
|
||||
$progress->setFormat(
|
||||
" %current:s%/%max:s% %bar% %percent:3s%%\n" .
|
||||
" " . ($message ? '%message%' : ' ') . " %elapsed:6s%/%estimated:-6s% %memory:6s%\n");
|
||||
$progress->setBarWidth(60);
|
||||
}
|
||||
|
||||
if (!defined('PHP_WINDOWS_VERSION_BUILD'))
|
||||
{
|
||||
$progress->setEmptyBarCharacter('░'); // light shade character \u2591
|
||||
$progress->setProgressCharacter('');
|
||||
$progress->setBarCharacter('▓'); // dark shade character \u2593
|
||||
}
|
||||
|
||||
return $progress;
|
||||
}
|
||||
}
|
||||
26
phpbb/console/command/config/command.php
Normal file
26
phpbb/console/command/config/command.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
namespace phpbb\console\command\config;
|
||||
|
||||
abstract class command extends \phpbb\console\command\command
|
||||
{
|
||||
/** @var \phpbb\config\config */
|
||||
protected $config;
|
||||
|
||||
public function __construct(\phpbb\user $user, \phpbb\config\config $config)
|
||||
{
|
||||
$this->config = $config;
|
||||
|
||||
parent::__construct($user);
|
||||
}
|
||||
}
|
||||
66
phpbb/console/command/config/delete.php
Normal file
66
phpbb/console/command/config/delete.php
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
namespace phpbb\console\command\config;
|
||||
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
class delete extends command
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('config:delete')
|
||||
->setDescription($this->user->lang('CLI_DESCRIPTION_DELETE_CONFIG'))
|
||||
->addArgument(
|
||||
'key',
|
||||
InputArgument::REQUIRED,
|
||||
$this->user->lang('CLI_CONFIG_OPTION_NAME')
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the command config:delete.
|
||||
*
|
||||
* Removes a configuration option
|
||||
*
|
||||
* @param InputInterface $input An InputInterface instance
|
||||
* @param OutputInterface $output An OutputInterface instance
|
||||
*
|
||||
* @return void
|
||||
* @see \phpbb\config\config::delete()
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
$key = $input->getArgument('key');
|
||||
|
||||
if (isset($this->config[$key]))
|
||||
{
|
||||
$this->config->delete($key);
|
||||
|
||||
$io->success($this->user->lang('CLI_CONFIG_DELETE_SUCCESS', $key));
|
||||
}
|
||||
else
|
||||
{
|
||||
$io->error($this->user->lang('CLI_CONFIG_NOT_EXISTS', $key));
|
||||
}
|
||||
}
|
||||
}
|
||||
75
phpbb/console/command/config/get.php
Normal file
75
phpbb/console/command/config/get.php
Normal file
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
namespace phpbb\console\command\config;
|
||||
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
class get extends command
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('config:get')
|
||||
->setDescription($this->user->lang('CLI_DESCRIPTION_GET_CONFIG'))
|
||||
->addArgument(
|
||||
'key',
|
||||
InputArgument::REQUIRED,
|
||||
$this->user->lang('CLI_CONFIG_OPTION_NAME')
|
||||
)
|
||||
->addOption(
|
||||
'no-newline',
|
||||
null,
|
||||
InputOption::VALUE_NONE,
|
||||
$this->user->lang('CLI_CONFIG_PRINT_WITHOUT_NEWLINE')
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the command config:get.
|
||||
*
|
||||
* Retrieves a configuration value.
|
||||
*
|
||||
* @param InputInterface $input An InputInterface instance
|
||||
* @param OutputInterface $output An OutputInterface instance
|
||||
*
|
||||
* @return void
|
||||
* @see \phpbb\config\config::offsetGet()
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
$key = $input->getArgument('key');
|
||||
|
||||
if (isset($this->config[$key]) && $input->getOption('no-newline'))
|
||||
{
|
||||
$output->write($this->config[$key]);
|
||||
}
|
||||
else if (isset($this->config[$key]))
|
||||
{
|
||||
$output->writeln($this->config[$key]);
|
||||
}
|
||||
else
|
||||
{
|
||||
$io->error($this->user->lang('CLI_CONFIG_NOT_EXISTS', $key));
|
||||
}
|
||||
}
|
||||
}
|
||||
73
phpbb/console/command/config/increment.php
Normal file
73
phpbb/console/command/config/increment.php
Normal file
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
namespace phpbb\console\command\config;
|
||||
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
class increment extends command
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('config:increment')
|
||||
->setDescription($this->user->lang('CLI_DESCRIPTION_INCREMENT_CONFIG'))
|
||||
->addArgument(
|
||||
'key',
|
||||
InputArgument::REQUIRED,
|
||||
$this->user->lang('CLI_CONFIG_OPTION_NAME')
|
||||
)
|
||||
->addArgument(
|
||||
'increment',
|
||||
InputArgument::REQUIRED,
|
||||
$this->user->lang('CLI_CONFIG_INCREMENT_BY')
|
||||
)
|
||||
->addOption(
|
||||
'dynamic',
|
||||
'd',
|
||||
InputOption::VALUE_NONE,
|
||||
$this->user->lang('CLI_CONFIG_CANNOT_CACHED')
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the command config:increment.
|
||||
*
|
||||
* Increments an integer configuration value.
|
||||
*
|
||||
* @param InputInterface $input An InputInterface instance
|
||||
* @param OutputInterface $output An OutputInterface instance
|
||||
*
|
||||
* @return void
|
||||
* @see \phpbb\config\config::increment()
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
$key = $input->getArgument('key');
|
||||
$increment = $input->getArgument('increment');
|
||||
$use_cache = !$input->getOption('dynamic');
|
||||
|
||||
$this->config->increment($key, $increment, $use_cache);
|
||||
|
||||
$io->success($this->user->lang('CLI_CONFIG_INCREMENT_SUCCESS', $key));
|
||||
}
|
||||
}
|
||||
73
phpbb/console/command/config/set.php
Normal file
73
phpbb/console/command/config/set.php
Normal file
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
namespace phpbb\console\command\config;
|
||||
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
class set extends command
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('config:set')
|
||||
->setDescription($this->user->lang('CLI_DESCRIPTION_SET_CONFIG'))
|
||||
->addArgument(
|
||||
'key',
|
||||
InputArgument::REQUIRED,
|
||||
$this->user->lang('CLI_CONFIG_OPTION_NAME')
|
||||
)
|
||||
->addArgument(
|
||||
'value',
|
||||
InputArgument::REQUIRED,
|
||||
$this->user->lang('CLI_CONFIG_NEW')
|
||||
)
|
||||
->addOption(
|
||||
'dynamic',
|
||||
'd',
|
||||
InputOption::VALUE_NONE,
|
||||
$this->user->lang('CLI_CONFIG_CANNOT_CACHED')
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the command config:set.
|
||||
*
|
||||
* Sets a configuration option's value.
|
||||
*
|
||||
* @param InputInterface $input An InputInterface instance
|
||||
* @param OutputInterface $output An OutputInterface instance
|
||||
*
|
||||
* @return void
|
||||
* @see \phpbb\config\config::set()
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
$key = $input->getArgument('key');
|
||||
$value = $input->getArgument('value');
|
||||
$use_cache = !$input->getOption('dynamic');
|
||||
|
||||
$this->config->set($key, $value, $use_cache);
|
||||
|
||||
$io->success($this->user->lang('CLI_CONFIG_SET_SUCCESS', $key));
|
||||
}
|
||||
}
|
||||
87
phpbb/console/command/config/set_atomic.php
Normal file
87
phpbb/console/command/config/set_atomic.php
Normal file
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
namespace phpbb\console\command\config;
|
||||
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
class set_atomic extends command
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('config:set-atomic')
|
||||
->setDescription($this->user->lang('CLI_DESCRIPTION_SET_ATOMIC_CONFIG'))
|
||||
->addArgument(
|
||||
'key',
|
||||
InputArgument::REQUIRED,
|
||||
$this->user->lang('CLI_CONFIG_OPTION_NAME')
|
||||
)
|
||||
->addArgument(
|
||||
'old',
|
||||
InputArgument::REQUIRED,
|
||||
$this->user->lang('CLI_CONFIG_CURRENT')
|
||||
)
|
||||
->addArgument(
|
||||
'new',
|
||||
InputArgument::REQUIRED,
|
||||
$this->user->lang('CLI_CONFIG_NEW')
|
||||
)
|
||||
->addOption(
|
||||
'dynamic',
|
||||
'd',
|
||||
InputOption::VALUE_NONE,
|
||||
$this->user->lang('CLI_CONFIG_CANNOT_CACHED')
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the command config:set-atomic.
|
||||
*
|
||||
* Sets a configuration option's value only if the old_value matches the
|
||||
* current configuration value or the configuration value does not exist yet.
|
||||
*
|
||||
* @param InputInterface $input An InputInterface instance
|
||||
* @param OutputInterface $output An OutputInterface instance
|
||||
*
|
||||
* @return bool True if the value was changed, false otherwise.
|
||||
* @see \phpbb\config\config::set_atomic()
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
$key = $input->getArgument('key');
|
||||
$old_value = $input->getArgument('old');
|
||||
$new_value = $input->getArgument('new');
|
||||
$use_cache = !$input->getOption('dynamic');
|
||||
|
||||
if ($this->config->set_atomic($key, $old_value, $new_value, $use_cache))
|
||||
{
|
||||
$io->success($this->user->lang('CLI_CONFIG_SET_SUCCESS', $key));
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
$io->error($this->user->lang('CLI_CONFIG_SET_FAILURE', $key));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
94
phpbb/console/command/cron/cron_list.php
Normal file
94
phpbb/console/command/cron/cron_list.php
Normal file
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
namespace phpbb\console\command\cron;
|
||||
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
class cron_list extends \phpbb\console\command\command
|
||||
{
|
||||
/** @var \phpbb\cron\manager */
|
||||
protected $cron_manager;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \phpbb\user $user User instance
|
||||
* @param \phpbb\cron\manager $cron_manager Cron manager
|
||||
*/
|
||||
public function __construct(\phpbb\user $user, \phpbb\cron\manager $cron_manager)
|
||||
{
|
||||
$this->cron_manager = $cron_manager;
|
||||
parent::__construct($user);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('cron:list')
|
||||
->setDescription($this->user->lang('CLI_DESCRIPTION_CRON_LIST'))
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the command cron:list.
|
||||
*
|
||||
* Prints a list of ready and unready cron jobs.
|
||||
*
|
||||
* @param InputInterface $input An InputInterface instance
|
||||
* @param OutputInterface $output An OutputInterface instance
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
$tasks = $this->cron_manager->get_tasks();
|
||||
|
||||
if (empty($tasks))
|
||||
{
|
||||
$io->error($this->user->lang('CRON_NO_TASKS'));
|
||||
return;
|
||||
}
|
||||
|
||||
$ready_tasks = $not_ready_tasks = array();
|
||||
foreach ($tasks as $task)
|
||||
{
|
||||
if ($task->is_ready())
|
||||
{
|
||||
$ready_tasks[] = $task->get_name();
|
||||
}
|
||||
else
|
||||
{
|
||||
$not_ready_tasks[] = $task->get_name();
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($ready_tasks))
|
||||
{
|
||||
$io->title($this->user->lang('TASKS_READY'));
|
||||
$io->listing($ready_tasks);
|
||||
}
|
||||
|
||||
if (!empty($not_ready_tasks))
|
||||
{
|
||||
$io->title($this->user->lang('TASKS_NOT_READY'));
|
||||
$io->listing($not_ready_tasks);
|
||||
}
|
||||
}
|
||||
}
|
||||
171
phpbb/console/command/cron/run.php
Normal file
171
phpbb/console/command/cron/run.php
Normal file
@@ -0,0 +1,171 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\console\command\cron;
|
||||
|
||||
use phpbb\exception\runtime_exception;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class run extends \phpbb\console\command\command
|
||||
{
|
||||
/** @var \phpbb\cron\manager */
|
||||
protected $cron_manager;
|
||||
|
||||
/** @var \phpbb\lock\db */
|
||||
protected $lock_db;
|
||||
|
||||
/**
|
||||
* Construct method
|
||||
*
|
||||
* @param \phpbb\user $user The user object (used to get language information)
|
||||
* @param \phpbb\cron\manager $cron_manager The cron manager containing
|
||||
* the cron tasks to be executed.
|
||||
* @param \phpbb\lock\db $lock_db The lock for accessing database.
|
||||
*/
|
||||
public function __construct(\phpbb\user $user, \phpbb\cron\manager $cron_manager, \phpbb\lock\db $lock_db)
|
||||
{
|
||||
$this->cron_manager = $cron_manager;
|
||||
$this->lock_db = $lock_db;
|
||||
parent::__construct($user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the command name and description
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('cron:run')
|
||||
->setDescription($this->user->lang('CLI_DESCRIPTION_CRON_RUN'))
|
||||
->setHelp($this->user->lang('CLI_HELP_CRON_RUN'))
|
||||
->addArgument('name', InputArgument::OPTIONAL, $this->user->lang('CLI_DESCRIPTION_CRON_RUN_ARGUMENT_1'))
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the command cron:run.
|
||||
*
|
||||
* Tries to acquire the cron lock, then if no argument has been given runs all ready cron tasks.
|
||||
* If the cron lock can not be obtained, an error message is printed
|
||||
* and the exit status is set to 1.
|
||||
* If the verbose option is specified, each start of a task is printed.
|
||||
* Otherwise there is no output.
|
||||
* If an argument is given to the command, only the task whose name matches the
|
||||
* argument will be started. If verbose option is specified,
|
||||
* an info message containing the name of the task is printed.
|
||||
* If no task matches the argument given, an error message is printed
|
||||
* and the exit status is set to 2.
|
||||
*
|
||||
* @param InputInterface $input The input stream used to get the argument and verboe option.
|
||||
* @param OutputInterface $output The output stream, used for printing verbose-mode and error information.
|
||||
*
|
||||
* @return int 0 if all is ok, 1 if a lock error occured and 2 if no task matching the argument was found.
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
if ($this->lock_db->acquire())
|
||||
{
|
||||
$task_name = $input->getArgument('name');
|
||||
if ($task_name)
|
||||
{
|
||||
$exit_status = $this->run_one($input, $output, $task_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
$exit_status = $this->run_all($input, $output);
|
||||
}
|
||||
|
||||
$this->lock_db->release();
|
||||
return $exit_status;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new runtime_exception('CRON_LOCK_ERROR', array(), null, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes all ready cron tasks.
|
||||
*
|
||||
* If verbose mode is set, an info message will be printed if there is no task to
|
||||
* be run, or else for each starting task.
|
||||
*
|
||||
* @see execute
|
||||
* @param InputInterface $input The input stream used to get the argument and verbose option.
|
||||
* @param OutputInterface $output The output stream, used for printing verbose-mode and error information.
|
||||
* @return int 0
|
||||
*/
|
||||
protected function run_all(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$run_tasks = $this->cron_manager->find_all_ready_tasks();
|
||||
|
||||
if ($run_tasks)
|
||||
{
|
||||
foreach ($run_tasks as $task)
|
||||
{
|
||||
if ($input->getOption('verbose'))
|
||||
{
|
||||
$output->writeln('<info>' . $this->user->lang('RUNNING_TASK', $task->get_name()) . '</info>');
|
||||
}
|
||||
|
||||
$task->run();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($input->getOption('verbose'))
|
||||
{
|
||||
$output->writeln('<info>' . $this->user->lang('CRON_NO_TASK') . '</info>');
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a given cron task, if it is ready.
|
||||
*
|
||||
* If there is a task whose name matches $task_name, it is run and 0 is returned.
|
||||
* and if verbose mode is set, print an info message with the name of the task.
|
||||
* If there is no task matching $task_name, the function prints an error message
|
||||
* and returns with status 2.
|
||||
*
|
||||
* @see execute
|
||||
* @param string $task_name The name of the task that should be run.
|
||||
* @param InputInterface $input The input stream used to get the argument and verbose option.
|
||||
* @param OutputInterface $output The output stream, used for printing verbose-mode and error information.
|
||||
* @return int 0 if all is well, 2 if no task matches $task_name.
|
||||
*/
|
||||
protected function run_one(InputInterface $input, OutputInterface $output, $task_name)
|
||||
{
|
||||
$task = $this->cron_manager->find_task($task_name);
|
||||
if ($task)
|
||||
{
|
||||
if ($input->getOption('verbose'))
|
||||
{
|
||||
$output->writeln('<info>' . $this->user->lang('RUNNING_TASK', $task_name) . '</info>');
|
||||
}
|
||||
|
||||
$task->run();
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new runtime_exception('CRON_NO_SUCH_TASK', array( $task_name), null, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
69
phpbb/console/command/db/console_migrator_output_handler.php
Normal file
69
phpbb/console/command/db/console_migrator_output_handler.php
Normal file
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\console\command\db;
|
||||
|
||||
use phpbb\db\output_handler\migrator_output_handler_interface;
|
||||
use phpbb\user;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class console_migrator_output_handler implements migrator_output_handler_interface
|
||||
{
|
||||
/**
|
||||
* User object.
|
||||
*
|
||||
* @var user
|
||||
*/
|
||||
private $user;
|
||||
|
||||
/**
|
||||
* Console output object.
|
||||
*
|
||||
* @var OutputInterface
|
||||
*/
|
||||
private $output;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param user $user User object
|
||||
* @param OutputInterface $output Console output object
|
||||
*/
|
||||
public function __construct(user $user, OutputInterface $output)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->output = $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function write($message, $verbosity)
|
||||
{
|
||||
if ($verbosity <= $this->output->getVerbosity())
|
||||
{
|
||||
$translated_message = call_user_func_array(array($this->user, 'lang'), $message);
|
||||
|
||||
if ($verbosity === migrator_output_handler_interface::VERBOSITY_NORMAL)
|
||||
{
|
||||
$translated_message = '<info>' . $translated_message . '</info>';
|
||||
}
|
||||
else if ($verbosity === migrator_output_handler_interface::VERBOSITY_VERBOSE)
|
||||
{
|
||||
$translated_message = '<comment>' . $translated_message . '</comment>';
|
||||
}
|
||||
|
||||
$this->output->writeln($translated_message);
|
||||
}
|
||||
}
|
||||
}
|
||||
81
phpbb/console/command/db/list_command.php
Normal file
81
phpbb/console/command/db/list_command.php
Normal file
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
namespace phpbb\console\command\db;
|
||||
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
class list_command extends \phpbb\console\command\db\migration_command
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('db:list')
|
||||
->setDescription($this->user->lang('CLI_DESCRIPTION_DB_LIST'))
|
||||
->addOption(
|
||||
'available',
|
||||
'u',
|
||||
InputOption::VALUE_NONE,
|
||||
$this->user->lang('CLI_MIGRATIONS_ONLY_AVAILABLE')
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
$show_installed = !$input->getOption('available');
|
||||
$installed = $available = array();
|
||||
|
||||
foreach ($this->load_migrations() as $name)
|
||||
{
|
||||
if ($this->migrator->migration_state($name) !== false)
|
||||
{
|
||||
$installed[] = $name;
|
||||
}
|
||||
else
|
||||
{
|
||||
$available[] = $name;
|
||||
}
|
||||
}
|
||||
|
||||
if ($show_installed)
|
||||
{
|
||||
$io->section($this->user->lang('CLI_MIGRATIONS_INSTALLED'));
|
||||
|
||||
if (!empty($installed))
|
||||
{
|
||||
$io->listing($installed);
|
||||
}
|
||||
else
|
||||
{
|
||||
$io->text($this->user->lang('CLI_MIGRATIONS_EMPTY'));
|
||||
$io->newLine();
|
||||
}
|
||||
}
|
||||
|
||||
$io->section($this->user->lang('CLI_MIGRATIONS_AVAILABLE'));
|
||||
if (!empty($available))
|
||||
{
|
||||
$io->listing($available);
|
||||
}
|
||||
else
|
||||
{
|
||||
$io->text($this->user->lang('CLI_MIGRATIONS_EMPTY'));
|
||||
$io->newLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
86
phpbb/console/command/db/migrate.php
Normal file
86
phpbb/console/command/db/migrate.php
Normal file
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
namespace phpbb\console\command\db;
|
||||
|
||||
use phpbb\db\output_handler\log_wrapper_migrator_output_handler;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
class migrate extends \phpbb\console\command\db\migration_command
|
||||
{
|
||||
/** @var \phpbb\log\log */
|
||||
protected $log;
|
||||
|
||||
/** @var string phpBB root path */
|
||||
protected $phpbb_root_path;
|
||||
|
||||
/** @var \phpbb\filesystem\filesystem_interface */
|
||||
protected $filesystem;
|
||||
|
||||
/** @var \phpbb\language\language */
|
||||
protected $language;
|
||||
|
||||
public function __construct(\phpbb\user $user, \phpbb\language\language $language, \phpbb\db\migrator $migrator, \phpbb\extension\manager $extension_manager, \phpbb\config\config $config, \phpbb\cache\service $cache, \phpbb\log\log $log, \phpbb\filesystem\filesystem_interface $filesystem, $phpbb_root_path)
|
||||
{
|
||||
$this->language = $language;
|
||||
$this->log = $log;
|
||||
$this->filesystem = $filesystem;
|
||||
$this->phpbb_root_path = $phpbb_root_path;
|
||||
parent::__construct($user, $migrator, $extension_manager, $config, $cache);
|
||||
$this->language->add_lang(array('common', 'install', 'migrator'));
|
||||
}
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('db:migrate')
|
||||
->setDescription($this->language->lang('CLI_DESCRIPTION_DB_MIGRATE'))
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
$this->migrator->set_output_handler(new log_wrapper_migrator_output_handler($this->language, new console_migrator_output_handler($this->user, $output), $this->phpbb_root_path . 'store/migrations_' . time() . '.log', $this->filesystem));
|
||||
|
||||
$this->migrator->create_migrations_table();
|
||||
|
||||
$this->cache->purge();
|
||||
|
||||
$this->load_migrations();
|
||||
$orig_version = $this->config['version'];
|
||||
while (!$this->migrator->finished())
|
||||
{
|
||||
try
|
||||
{
|
||||
$this->migrator->update();
|
||||
}
|
||||
catch (\phpbb\db\migration\exception $e)
|
||||
{
|
||||
$io->error($e->getLocalisedMessage($this->user));
|
||||
$this->finalise_update();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if ($orig_version != $this->config['version'])
|
||||
{
|
||||
$this->log->add('admin', ANONYMOUS, '', 'LOG_UPDATE_DATABASE', time(), array($orig_version, $this->config['version']));
|
||||
}
|
||||
|
||||
$this->finalise_update();
|
||||
$io->success($this->language->lang('INLINE_UPDATE_SUCCESSFUL'));
|
||||
}
|
||||
}
|
||||
56
phpbb/console/command/db/migration_command.php
Normal file
56
phpbb/console/command/db/migration_command.php
Normal file
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
namespace phpbb\console\command\db;
|
||||
|
||||
abstract class migration_command extends \phpbb\console\command\command
|
||||
{
|
||||
/** @var \phpbb\db\migrator */
|
||||
protected $migrator;
|
||||
|
||||
/** @var \phpbb\extension\manager */
|
||||
protected $extension_manager;
|
||||
|
||||
/** @var \phpbb\config\config */
|
||||
protected $config;
|
||||
|
||||
/** @var \phpbb\cache\service */
|
||||
protected $cache;
|
||||
|
||||
public function __construct(\phpbb\user $user, \phpbb\db\migrator $migrator, \phpbb\extension\manager $extension_manager, \phpbb\config\config $config, \phpbb\cache\service $cache)
|
||||
{
|
||||
$this->migrator = $migrator;
|
||||
$this->extension_manager = $extension_manager;
|
||||
$this->config = $config;
|
||||
$this->cache = $cache;
|
||||
parent::__construct($user);
|
||||
}
|
||||
|
||||
protected function load_migrations()
|
||||
{
|
||||
$migrations = $this->extension_manager
|
||||
->get_finder()
|
||||
->core_path('phpbb/db/migration/data/')
|
||||
->extension_directory('/migrations')
|
||||
->get_classes();
|
||||
|
||||
$this->migrator->set_migrations($migrations);
|
||||
|
||||
return $this->migrator->get_migrations();
|
||||
}
|
||||
|
||||
protected function finalise_update()
|
||||
{
|
||||
$this->cache->purge();
|
||||
$this->config->increment('assets_version', 1);
|
||||
}
|
||||
}
|
||||
74
phpbb/console/command/db/revert.php
Normal file
74
phpbb/console/command/db/revert.php
Normal file
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
namespace phpbb\console\command\db;
|
||||
|
||||
use phpbb\db\output_handler\log_wrapper_migrator_output_handler;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
class revert extends \phpbb\console\command\db\migrate
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('db:revert')
|
||||
->setDescription($this->language->lang('CLI_DESCRIPTION_DB_REVERT'))
|
||||
->addArgument(
|
||||
'name',
|
||||
InputArgument::REQUIRED,
|
||||
$this->language->lang('CLI_MIGRATION_NAME')
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
$name = str_replace('/', '\\', $input->getArgument('name'));
|
||||
|
||||
$this->migrator->set_output_handler(new log_wrapper_migrator_output_handler($this->language, new console_migrator_output_handler($this->user, $output), $this->phpbb_root_path . 'store/migrations_' . time() . '.log', $this->filesystem));
|
||||
|
||||
$this->cache->purge();
|
||||
|
||||
if (!in_array($name, $this->load_migrations()))
|
||||
{
|
||||
$io->error($this->language->lang('MIGRATION_NOT_VALID', $name));
|
||||
return 1;
|
||||
}
|
||||
else if ($this->migrator->migration_state($name) === false)
|
||||
{
|
||||
$io->error($this->language->lang('MIGRATION_NOT_INSTALLED', $name));
|
||||
return 1;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
while ($this->migrator->migration_state($name) !== false)
|
||||
{
|
||||
$this->migrator->revert($name);
|
||||
}
|
||||
}
|
||||
catch (\phpbb\db\migration\exception $e)
|
||||
{
|
||||
$io->error($e->getLocalisedMessage($this->user));
|
||||
$this->finalise_update();
|
||||
return 1;
|
||||
}
|
||||
|
||||
$this->finalise_update();
|
||||
$io->success($this->language->lang('INLINE_UPDATE_SUCCESSFUL'));
|
||||
}
|
||||
}
|
||||
64
phpbb/console/command/dev/migration_tips.php
Normal file
64
phpbb/console/command/dev/migration_tips.php
Normal file
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
namespace phpbb\console\command\dev;
|
||||
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class migration_tips extends \phpbb\console\command\command
|
||||
{
|
||||
/** @var \phpbb\extension\manager */
|
||||
protected $extension_manager;
|
||||
|
||||
public function __construct(\phpbb\user $user, \phpbb\extension\manager $extension_manager)
|
||||
{
|
||||
$this->extension_manager = $extension_manager;
|
||||
parent::__construct($user);
|
||||
}
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('dev:migration-tips')
|
||||
->setDescription($this->user->lang('CLI_DESCRIPTION_FIND_MIGRATIONS'))
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$migrations = $this->extension_manager->get_finder()
|
||||
->set_extensions(array())
|
||||
->core_path('phpbb/db/migration/data/')
|
||||
->get_classes();
|
||||
$tips = $migrations;
|
||||
|
||||
foreach ($migrations as $migration_class)
|
||||
{
|
||||
foreach ($migration_class::depends_on() as $dependency)
|
||||
{
|
||||
$tips_key = array_search($dependency, $tips);
|
||||
if ($tips_key !== false)
|
||||
{
|
||||
unset($tips[$tips_key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$output->writeln("\t\tarray(");
|
||||
foreach ($tips as $migration)
|
||||
{
|
||||
$output->writeln("\t\t\t'{$migration}',");
|
||||
}
|
||||
$output->writeln("\t\t);");
|
||||
}
|
||||
}
|
||||
30
phpbb/console/command/extension/command.php
Normal file
30
phpbb/console/command/extension/command.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
namespace phpbb\console\command\extension;
|
||||
|
||||
abstract class command extends \phpbb\console\command\command
|
||||
{
|
||||
/** @var \phpbb\extension\manager */
|
||||
protected $manager;
|
||||
|
||||
/** @var \phpbb\log\log */
|
||||
protected $log;
|
||||
|
||||
public function __construct(\phpbb\user $user, \phpbb\extension\manager $manager, \phpbb\log\log $log)
|
||||
{
|
||||
$this->manager = $manager;
|
||||
$this->log = $log;
|
||||
|
||||
parent::__construct($user);
|
||||
}
|
||||
}
|
||||
62
phpbb/console/command/extension/disable.php
Normal file
62
phpbb/console/command/extension/disable.php
Normal file
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
namespace phpbb\console\command\extension;
|
||||
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
class disable extends command
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('extension:disable')
|
||||
->setDescription($this->user->lang('CLI_DESCRIPTION_DISABLE_EXTENSION'))
|
||||
->addArgument(
|
||||
'extension-name',
|
||||
InputArgument::REQUIRED,
|
||||
$this->user->lang('CLI_EXTENSION_NAME')
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
$name = $input->getArgument('extension-name');
|
||||
|
||||
if (!$this->manager->is_enabled($name))
|
||||
{
|
||||
$io->error($this->user->lang('CLI_EXTENSION_DISABLED', $name));
|
||||
return 2;
|
||||
}
|
||||
|
||||
$this->manager->disable($name);
|
||||
$this->manager->load_extensions();
|
||||
|
||||
if ($this->manager->is_enabled($name))
|
||||
{
|
||||
$io->error($this->user->lang('CLI_EXTENSION_DISABLE_FAILURE', $name));
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->log->add('admin', ANONYMOUS, '', 'LOG_EXT_DISABLE', time(), array($name));
|
||||
$io->success($this->user->lang('CLI_EXTENSION_DISABLE_SUCCESS', $name));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
76
phpbb/console/command/extension/enable.php
Normal file
76
phpbb/console/command/extension/enable.php
Normal file
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
namespace phpbb\console\command\extension;
|
||||
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
class enable extends command
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('extension:enable')
|
||||
->setDescription($this->user->lang('CLI_DESCRIPTION_ENABLE_EXTENSION'))
|
||||
->addArgument(
|
||||
'extension-name',
|
||||
InputArgument::REQUIRED,
|
||||
$this->user->lang('CLI_EXTENSION_NAME')
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
$name = $input->getArgument('extension-name');
|
||||
|
||||
if (!$this->manager->is_available($name))
|
||||
{
|
||||
$io->error($this->user->lang('CLI_EXTENSION_NOT_EXIST', $name));
|
||||
return 1;
|
||||
}
|
||||
|
||||
$extension = $this->manager->get_extension($name);
|
||||
|
||||
if (!$extension->is_enableable())
|
||||
{
|
||||
$io->error($this->user->lang('CLI_EXTENSION_NOT_ENABLEABLE', $name));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ($this->manager->is_enabled($name))
|
||||
{
|
||||
$io->error($this->user->lang('CLI_EXTENSION_ENABLED', $name));
|
||||
return 1;
|
||||
}
|
||||
|
||||
$this->manager->enable($name);
|
||||
$this->manager->load_extensions();
|
||||
|
||||
if ($this->manager->is_enabled($name))
|
||||
{
|
||||
$this->log->add('admin', ANONYMOUS, '', 'LOG_EXT_ENABLE', time(), array($name));
|
||||
$io->success($this->user->lang('CLI_EXTENSION_ENABLE_SUCCESS', $name));
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
$io->error($this->user->lang('CLI_EXTENSION_ENABLE_FAILURE', $name));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
55
phpbb/console/command/extension/purge.php
Normal file
55
phpbb/console/command/extension/purge.php
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
namespace phpbb\console\command\extension;
|
||||
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
class purge extends command
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('extension:purge')
|
||||
->setDescription($this->user->lang('CLI_DESCRIPTION_PURGE_EXTENSION'))
|
||||
->addArgument(
|
||||
'extension-name',
|
||||
InputArgument::REQUIRED,
|
||||
$this->user->lang('CLI_EXTENSION_NAME')
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
$name = $input->getArgument('extension-name');
|
||||
$this->manager->purge($name);
|
||||
$this->manager->load_extensions();
|
||||
|
||||
if ($this->manager->is_enabled($name))
|
||||
{
|
||||
$io->error($this->user->lang('CLI_EXTENSION_PURGE_FAILURE', $name));
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->log->add('admin', ANONYMOUS, '', 'LOG_EXT_PURGE', time(), array($name));
|
||||
$io->success($this->user->lang('CLI_EXTENSION_PURGE_SUCCESS', $name));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
54
phpbb/console/command/extension/show.php
Normal file
54
phpbb/console/command/extension/show.php
Normal file
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
namespace phpbb\console\command\extension;
|
||||
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
class show extends command
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('extension:show')
|
||||
->setDescription($this->user->lang('CLI_DESCRIPTION_LIST_EXTENSIONS'))
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
$this->manager->load_extensions();
|
||||
$all = array_keys($this->manager->all_available());
|
||||
|
||||
if (empty($all))
|
||||
{
|
||||
$io->note($this->user->lang('CLI_EXTENSION_NOT_FOUND'));
|
||||
return 3;
|
||||
}
|
||||
|
||||
$enabled = array_keys($this->manager->all_enabled());
|
||||
$io->section($this->user->lang('CLI_EXTENSIONS_ENABLED'));
|
||||
$io->listing($enabled);
|
||||
|
||||
$disabled = array_keys($this->manager->all_disabled());
|
||||
$io->section($this->user->lang('CLI_EXTENSIONS_DISABLED'));
|
||||
$io->listing($disabled);
|
||||
|
||||
$purged = array_diff($all, $enabled, $disabled);
|
||||
$io->section($this->user->lang('CLI_EXTENSIONS_AVAILABLE'));
|
||||
$io->listing($purged);
|
||||
}
|
||||
}
|
||||
137
phpbb/console/command/fixup/fix_left_right_ids.php
Normal file
137
phpbb/console/command/fixup/fix_left_right_ids.php
Normal file
@@ -0,0 +1,137 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\console\command\fixup;
|
||||
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
class fix_left_right_ids extends \phpbb\console\command\command
|
||||
{
|
||||
/** @var \phpbb\user */
|
||||
protected $user;
|
||||
|
||||
/** @var \phpbb\db\driver\driver_interface */
|
||||
protected $db;
|
||||
|
||||
/** @var \phpbb\cache\driver\driver_interface */
|
||||
protected $cache;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \phpbb\user $user User instance
|
||||
* @param \phpbb\db\driver\driver_interface $db Database connection
|
||||
* @param \phpbb\cache\driver\driver_interface $cache Cache instance
|
||||
*/
|
||||
public function __construct(\phpbb\user $user, \phpbb\db\driver\driver_interface $db, \phpbb\cache\driver\driver_interface $cache)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->db = $db;
|
||||
$this->cache = $cache;
|
||||
|
||||
parent::__construct($user);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('fixup:fix-left-right-ids')
|
||||
->setDescription($this->user->lang('CLI_DESCRIPTION_FIX_LEFT_RIGHT_IDS'))
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the command fixup:fix-left-right-ids.
|
||||
*
|
||||
* Repairs the tree structure of the forums and modules.
|
||||
* The code is mainly borrowed from Support toolkit for phpBB Olympus
|
||||
*
|
||||
* @param InputInterface $input An InputInterface instance
|
||||
* @param OutputInterface $output An OutputInterface instance
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
// Fix Left/Right IDs for the modules table
|
||||
$result = $this->db->sql_query('SELECT DISTINCT(module_class) FROM ' . MODULES_TABLE);
|
||||
while ($row = $this->db->sql_fetchrow($result))
|
||||
{
|
||||
$i = 1;
|
||||
$where = array("module_class = '" . $this->db->sql_escape($row['module_class']) . "'");
|
||||
$this->fix_ids_tree($i, 'module_id', MODULES_TABLE, 0, $where);
|
||||
}
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
// Fix the Left/Right IDs for the forums table
|
||||
$i = 1;
|
||||
$this->fix_ids_tree($i, 'forum_id', FORUMS_TABLE);
|
||||
|
||||
$this->cache->purge();
|
||||
|
||||
$io->success($this->user->lang('CLI_FIXUP_FIX_LEFT_RIGHT_IDS_SUCCESS'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Item's tree structure rebuild helper
|
||||
* The item is either forum or ACP/MCP/UCP module
|
||||
*
|
||||
* @param int $i Item id offset index
|
||||
* @param string $field The key field to fix, forum_id|module_id
|
||||
* @param string $table The table name to perform, FORUMS_TABLE|MODULES_TABLE
|
||||
* @param int $parent_id Parent item id
|
||||
* @param array $where Additional WHERE clause condition
|
||||
*
|
||||
* @return bool True on rebuild success, false otherwise
|
||||
*/
|
||||
protected function fix_ids_tree(&$i, $field, $table, $parent_id = 0, $where = array())
|
||||
{
|
||||
$changes_made = false;
|
||||
$sql = 'SELECT * FROM ' . $table . '
|
||||
WHERE parent_id = ' . (int) $parent_id .
|
||||
((!empty($where)) ? ' AND ' . implode(' AND ', $where) : '') . '
|
||||
ORDER BY left_id ASC';
|
||||
$result = $this->db->sql_query($sql);
|
||||
while ($row = $this->db->sql_fetchrow($result))
|
||||
{
|
||||
// Update the left_id for the item
|
||||
if ($row['left_id'] != $i)
|
||||
{
|
||||
$this->db->sql_query('UPDATE ' . $table . ' SET ' . $this->db->sql_build_array('UPDATE', array('left_id' => $i)) . " WHERE $field = " . (int) $row[$field]);
|
||||
$changes_made = true;
|
||||
}
|
||||
$i++;
|
||||
|
||||
// Go through children and update their left/right IDs
|
||||
$changes_made = (($this->fix_ids_tree($i, $field, $table, $row[$field], $where)) || $changes_made) ? true : false;
|
||||
|
||||
// Update the right_id for the item
|
||||
if ($row['right_id'] != $i)
|
||||
{
|
||||
$this->db->sql_query('UPDATE ' . $table . ' SET ' . $this->db->sql_build_array('UPDATE', array('right_id' => $i)) . " WHERE $field = " . (int) $row[$field]);
|
||||
$changes_made = true;
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
return $changes_made;
|
||||
}
|
||||
}
|
||||
76
phpbb/console/command/fixup/recalculate_email_hash.php
Normal file
76
phpbb/console/command/fixup/recalculate_email_hash.php
Normal file
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
namespace phpbb\console\command\fixup;
|
||||
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
class recalculate_email_hash extends \phpbb\console\command\command
|
||||
{
|
||||
/** @var \phpbb\db\driver\driver_interface */
|
||||
protected $db;
|
||||
|
||||
public function __construct(\phpbb\user $user, \phpbb\db\driver\driver_interface $db)
|
||||
{
|
||||
$this->db = $db;
|
||||
|
||||
parent::__construct($user);
|
||||
}
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('fixup:recalculate-email-hash')
|
||||
->setDescription($this->user->lang('CLI_DESCRIPTION_RECALCULATE_EMAIL_HASH'))
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
$sql = 'SELECT user_id, user_email, user_email_hash
|
||||
FROM ' . USERS_TABLE . '
|
||||
WHERE user_type <> ' . USER_IGNORE . "
|
||||
AND user_email <> ''";
|
||||
$result = $this->db->sql_query($sql);
|
||||
|
||||
while ($row = $this->db->sql_fetchrow($result))
|
||||
{
|
||||
$user_email_hash = phpbb_email_hash($row['user_email']);
|
||||
if ($user_email_hash !== $row['user_email_hash'])
|
||||
{
|
||||
$sql_ary = array(
|
||||
'user_email_hash' => $user_email_hash,
|
||||
);
|
||||
|
||||
$sql = 'UPDATE ' . USERS_TABLE . '
|
||||
SET ' . $this->db->sql_build_array('UPDATE', $sql_ary) . '
|
||||
WHERE user_id = ' . (int) $row['user_id'];
|
||||
$this->db->sql_query($sql);
|
||||
|
||||
if ($output->getVerbosity() >= OutputInterface::VERBOSITY_DEBUG)
|
||||
{
|
||||
$io->table(
|
||||
array('user_id', 'user_email', 'user_email_hash'),
|
||||
array(array($row['user_id'], $row['user_email'], $user_email_hash))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
$io->success($this->user->lang('CLI_FIXUP_RECALCULATE_EMAIL_HASH_SUCCESS'));
|
||||
}
|
||||
}
|
||||
117
phpbb/console/command/fixup/update_hashes.php
Normal file
117
phpbb/console/command/fixup/update_hashes.php
Normal file
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
namespace phpbb\console\command\fixup;
|
||||
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Helper\ProgressBar;
|
||||
|
||||
class update_hashes extends \phpbb\console\command\command
|
||||
{
|
||||
/** @var \phpbb\config\config */
|
||||
protected $config;
|
||||
|
||||
/** @var \phpbb\db\driver\driver_interface */
|
||||
protected $db;
|
||||
|
||||
/** @var \phpbb\passwords\manager */
|
||||
protected $passwords_manager;
|
||||
|
||||
/** @var string Default hashing type */
|
||||
protected $default_type;
|
||||
|
||||
/**
|
||||
* Update_hashes constructor
|
||||
*
|
||||
* @param \phpbb\config\config $config
|
||||
* @param \phpbb\user $user
|
||||
* @param \phpbb\db\driver\driver_interface $db
|
||||
* @param \phpbb\passwords\manager $passwords_manager
|
||||
* @param array $hashing_algorithms Hashing driver
|
||||
* service collection
|
||||
* @param array $defaults Default password types
|
||||
*/
|
||||
public function __construct(\phpbb\config\config $config, \phpbb\user $user,
|
||||
\phpbb\db\driver\driver_interface $db, \phpbb\passwords\manager $passwords_manager,
|
||||
$hashing_algorithms, $defaults)
|
||||
{
|
||||
$this->config = $config;
|
||||
$this->db = $db;
|
||||
|
||||
$this->passwords_manager = $passwords_manager;
|
||||
|
||||
foreach ($defaults as $type)
|
||||
{
|
||||
if ($hashing_algorithms[$type]->is_supported())
|
||||
{
|
||||
$this->default_type = $type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
parent::__construct($user);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('fixup:update-hashes')
|
||||
->setDescription($this->user->lang('CLI_DESCRIPTION_UPDATE_HASH_BCRYPT'))
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
// Get count to be able to display progress
|
||||
$sql = 'SELECT COUNT(user_id) AS count
|
||||
FROM ' . USERS_TABLE . '
|
||||
WHERE user_password ' . $this->db->sql_like_expression('$H$' . $this->db->get_any_char()) . '
|
||||
OR user_password ' . $this->db->sql_like_expression('$CP$' . $this->db->get_any_char());
|
||||
$result = $this->db->sql_query($sql);
|
||||
$total_update_passwords = $this->db->sql_fetchfield('count');
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
// Create progress bar
|
||||
$progress_bar = new ProgressBar($output, $total_update_passwords);
|
||||
$progress_bar->start();
|
||||
|
||||
$sql = 'SELECT user_id, user_password
|
||||
FROM ' . USERS_TABLE . '
|
||||
WHERE user_password ' . $this->db->sql_like_expression('$H$' . $this->db->get_any_char()) . '
|
||||
OR user_password ' . $this->db->sql_like_expression('$CP$' . $this->db->get_any_char());
|
||||
$result = $this->db->sql_query($sql);
|
||||
|
||||
while ($row = $this->db->sql_fetchrow($result))
|
||||
{
|
||||
$new_hash = $this->passwords_manager->hash($row['user_password'], array($this->default_type));
|
||||
|
||||
$sql = 'UPDATE ' . USERS_TABLE . "
|
||||
SET user_password = '" . $this->db->sql_escape($new_hash) . "'
|
||||
WHERE user_id = " . (int) $row['user_id'];
|
||||
$this->db->sql_query($sql);
|
||||
$progress_bar->advance();
|
||||
}
|
||||
|
||||
$this->config->set('update_hashes_last_cron', time());
|
||||
|
||||
$progress_bar->finish();
|
||||
|
||||
$output->writeln('<info>' . $this->user->lang('CLI_FIXUP_UPDATE_HASH_BCRYPT_SUCCESS') . '</info>');
|
||||
}
|
||||
}
|
||||
72
phpbb/console/command/reparser/list_all.php
Normal file
72
phpbb/console/command/reparser/list_all.php
Normal file
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\console\command\reparser;
|
||||
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
class list_all extends \phpbb\console\command\command
|
||||
{
|
||||
/**
|
||||
* @var string[] Names of the reparser services
|
||||
*/
|
||||
protected $reparser_names;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \phpbb\user $user
|
||||
* @param \phpbb\di\service_collection $reparsers
|
||||
*/
|
||||
public function __construct(\phpbb\user $user, \phpbb\di\service_collection $reparsers)
|
||||
{
|
||||
parent::__construct($user);
|
||||
$this->reparser_names = array();
|
||||
foreach ($reparsers as $reparser)
|
||||
{
|
||||
// Store the names without the "text_reparser." prefix
|
||||
$this->reparser_names[] = $reparser->get_name();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the command name and description
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('reparser:list')
|
||||
->setDescription($this->user->lang('CLI_DESCRIPTION_REPARSER_LIST'))
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the command reparser:list
|
||||
*
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return integer
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$io->section($this->user->lang('CLI_DESCRIPTION_REPARSER_AVAILABLE'));
|
||||
$io->listing($this->reparser_names);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
242
phpbb/console/command/reparser/reparse.php
Normal file
242
phpbb/console/command/reparser/reparse.php
Normal file
@@ -0,0 +1,242 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\console\command\reparser;
|
||||
|
||||
use phpbb\exception\runtime_exception;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
class reparse extends \phpbb\console\command\command
|
||||
{
|
||||
/**
|
||||
* @var InputInterface
|
||||
*/
|
||||
protected $input;
|
||||
|
||||
/**
|
||||
* @var SymfonyStyle
|
||||
*/
|
||||
protected $io;
|
||||
|
||||
/**
|
||||
* @var OutputInterface
|
||||
*/
|
||||
protected $output;
|
||||
|
||||
/**
|
||||
* @var \phpbb\lock\db
|
||||
*/
|
||||
protected $reparse_lock;
|
||||
|
||||
/**
|
||||
* @var \phpbb\textreparser\manager
|
||||
*/
|
||||
protected $reparser_manager;
|
||||
|
||||
/**
|
||||
* @var \phpbb\di\service_collection
|
||||
*/
|
||||
protected $reparsers;
|
||||
|
||||
/**
|
||||
* @var array The reparser's last $current ID as values
|
||||
*/
|
||||
protected $resume_data;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \phpbb\user $user
|
||||
* @param \phpbb\lock\db $reparse_lock
|
||||
* @param \phpbb\textreparser\manager $reparser_manager
|
||||
* @param \phpbb\di\service_collection $reparsers
|
||||
*/
|
||||
public function __construct(\phpbb\user $user, \phpbb\lock\db $reparse_lock, \phpbb\textreparser\manager $reparser_manager, \phpbb\di\service_collection $reparsers)
|
||||
{
|
||||
require_once __DIR__ . '/../../../../includes/functions_content.php';
|
||||
|
||||
$this->reparse_lock = $reparse_lock;
|
||||
$this->reparser_manager = $reparser_manager;
|
||||
$this->reparsers = $reparsers;
|
||||
parent::__construct($user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the command name and description
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('reparser:reparse')
|
||||
->setDescription($this->user->lang('CLI_DESCRIPTION_REPARSER_REPARSE'))
|
||||
->addArgument('reparser-name', InputArgument::OPTIONAL, $this->user->lang('CLI_DESCRIPTION_REPARSER_REPARSE_ARG_1'))
|
||||
->addOption(
|
||||
'dry-run',
|
||||
null,
|
||||
InputOption::VALUE_NONE,
|
||||
$this->user->lang('CLI_DESCRIPTION_REPARSER_REPARSE_OPT_DRY_RUN')
|
||||
)
|
||||
->addOption(
|
||||
'resume',
|
||||
null,
|
||||
InputOption::VALUE_NONE,
|
||||
$this->user->lang('CLI_DESCRIPTION_REPARSER_REPARSE_OPT_RESUME')
|
||||
)
|
||||
->addOption(
|
||||
'range-min',
|
||||
null,
|
||||
InputOption::VALUE_REQUIRED,
|
||||
$this->user->lang('CLI_DESCRIPTION_REPARSER_REPARSE_OPT_RANGE_MIN'),
|
||||
1
|
||||
)
|
||||
->addOption(
|
||||
'range-max',
|
||||
null,
|
||||
InputOption::VALUE_REQUIRED,
|
||||
$this->user->lang('CLI_DESCRIPTION_REPARSER_REPARSE_OPT_RANGE_MAX')
|
||||
)
|
||||
->addOption(
|
||||
'range-size',
|
||||
null,
|
||||
InputOption::VALUE_REQUIRED,
|
||||
$this->user->lang('CLI_DESCRIPTION_REPARSER_REPARSE_OPT_RANGE_SIZE'),
|
||||
100
|
||||
);
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the command reparser:reparse
|
||||
*
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return integer
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$this->input = $input;
|
||||
$this->output = $output;
|
||||
$this->io = new SymfonyStyle($input, $output);
|
||||
|
||||
if (!$this->reparse_lock->acquire())
|
||||
{
|
||||
throw new runtime_exception('REPARSE_LOCK_ERROR', array(), null, 1);
|
||||
}
|
||||
|
||||
$name = $input->getArgument('reparser-name');
|
||||
if ($name)
|
||||
{
|
||||
$name = $this->reparser_manager->find_reparser($name);
|
||||
$this->reparse($name);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach ($this->reparsers as $name => $service)
|
||||
{
|
||||
$this->reparse($name);
|
||||
}
|
||||
}
|
||||
|
||||
$this->io->success($this->user->lang('CLI_REPARSER_REPARSE_SUCCESS'));
|
||||
|
||||
$this->reparse_lock->release();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an option value, adjusted for given reparser
|
||||
*
|
||||
* Will use the last saved value if --resume is set and the option was not specified
|
||||
* on the command line
|
||||
*
|
||||
* @param string $option_name Option name
|
||||
* @return integer
|
||||
*/
|
||||
protected function get_option($option_name)
|
||||
{
|
||||
// Return the option from the resume_data if applicable
|
||||
if ($this->input->getOption('resume') && isset($this->resume_data[$option_name]) && !$this->input->hasParameterOption('--' . $option_name))
|
||||
{
|
||||
return $this->resume_data[$option_name];
|
||||
}
|
||||
|
||||
return $this->input->getOption($option_name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reparse all text handled by given reparser within given range
|
||||
*
|
||||
* @param string $name Reparser service name
|
||||
*/
|
||||
protected function reparse($name)
|
||||
{
|
||||
$reparser = $this->reparsers[$name];
|
||||
$this->resume_data = $this->reparser_manager->get_resume_data($name);
|
||||
if ($this->input->getOption('dry-run'))
|
||||
{
|
||||
$reparser->disable_save();
|
||||
}
|
||||
else
|
||||
{
|
||||
$reparser->enable_save();
|
||||
}
|
||||
|
||||
// Start at range-max if specified or at the highest ID otherwise
|
||||
$max = $this->get_option('range-max');
|
||||
$min = $this->get_option('range-min');
|
||||
$size = $this->get_option('range-size');
|
||||
|
||||
// range-max has no default value, it must be computed for each reparser
|
||||
if ($max === null)
|
||||
{
|
||||
$max = $reparser->get_max_id();
|
||||
}
|
||||
|
||||
if ($max < $min)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$this->io->section($this->user->lang('CLI_REPARSER_REPARSE_REPARSING', $reparser->get_name(), $min, $max));
|
||||
|
||||
$progress = $this->create_progress_bar($max, $this->io, $this->output, true);
|
||||
$progress->setMessage($this->user->lang('CLI_REPARSER_REPARSE_REPARSING_START', $reparser->get_name()));
|
||||
$progress->start();
|
||||
|
||||
// Start from $max and decrement $current by $size until we reach $min
|
||||
$current = $max;
|
||||
while ($current >= $min)
|
||||
{
|
||||
$start = max($min, $current + 1 - $size);
|
||||
$end = max($min, $current);
|
||||
|
||||
$progress->setMessage($this->user->lang('CLI_REPARSER_REPARSE_REPARSING', $reparser->get_name(), $start, $end));
|
||||
$reparser->reparse_range($start, $end);
|
||||
|
||||
$current = $start - 1;
|
||||
$progress->setProgress($max + 1 - $start);
|
||||
|
||||
$this->reparser_manager->update_resume_data($name, $min, $current, $size, !$this->input->getOption('dry-run'));
|
||||
}
|
||||
$progress->finish();
|
||||
|
||||
$this->io->newLine(2);
|
||||
}
|
||||
}
|
||||
160
phpbb/console/command/thumbnail/delete.php
Normal file
160
phpbb/console/command/thumbnail/delete.php
Normal file
@@ -0,0 +1,160 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
namespace phpbb\console\command\thumbnail;
|
||||
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
class delete extends \phpbb\console\command\command
|
||||
{
|
||||
/**
|
||||
* @var \phpbb\config\config
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* @var \phpbb\db\driver\driver_interface
|
||||
*/
|
||||
protected $db;
|
||||
|
||||
/**
|
||||
* phpBB root path
|
||||
* @var string
|
||||
*/
|
||||
protected $phpbb_root_path;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \config\config $config The config
|
||||
* @param \phpbb\user $user The user object (used to get language information)
|
||||
* @param \phpbb\db\driver\driver_interface $db Database connection
|
||||
* @param string $phpbb_root_path Root path
|
||||
*/
|
||||
public function __construct(\phpbb\config\config $config, \phpbb\user $user, \phpbb\db\driver\driver_interface $db, $phpbb_root_path)
|
||||
{
|
||||
$this->config = $config;
|
||||
$this->db = $db;
|
||||
$this->phpbb_root_path = $phpbb_root_path;
|
||||
|
||||
parent::__construct($user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the command name and description
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('thumbnail:delete')
|
||||
->setDescription($this->user->lang('CLI_DESCRIPTION_THUMBNAIL_DELETE'))
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the command thumbnail:delete.
|
||||
*
|
||||
* Deletes all existing thumbnails and updates the database accordingly.
|
||||
*
|
||||
* @param InputInterface $input The input stream used to get the argument and verbose option.
|
||||
* @param OutputInterface $output The output stream, used for printing verbose-mode and error information.
|
||||
*
|
||||
* @return int 0 if all is ok, 1 if a thumbnail couldn't be deleted.
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
$io->section($this->user->lang('CLI_THUMBNAIL_DELETING'));
|
||||
|
||||
$sql = 'SELECT COUNT(*) AS nb_missing_thumbnails
|
||||
FROM ' . ATTACHMENTS_TABLE . '
|
||||
WHERE thumbnail = 1';
|
||||
$result = $this->db->sql_query($sql);
|
||||
$nb_missing_thumbnails = (int) $this->db->sql_fetchfield('nb_missing_thumbnails');
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
if ($nb_missing_thumbnails === 0)
|
||||
{
|
||||
$io->warning($this->user->lang('CLI_THUMBNAIL_NOTHING_TO_DELETE'));
|
||||
return 0;
|
||||
}
|
||||
|
||||
$sql = 'SELECT attach_id, physical_filename, extension, real_filename, mimetype
|
||||
FROM ' . ATTACHMENTS_TABLE . '
|
||||
WHERE thumbnail = 1';
|
||||
$result = $this->db->sql_query($sql);
|
||||
|
||||
$progress = $this->create_progress_bar($nb_missing_thumbnails, $io, $output);
|
||||
|
||||
$progress->setMessage($this->user->lang('CLI_THUMBNAIL_DELETING'));
|
||||
|
||||
$progress->start();
|
||||
|
||||
$thumbnail_deleted = array();
|
||||
$return = 0;
|
||||
while ($row = $this->db->sql_fetchrow($result))
|
||||
{
|
||||
$thumbnail_path = $this->phpbb_root_path . $this->config['upload_path'] . '/thumb_' . $row['physical_filename'];
|
||||
|
||||
if (@unlink($thumbnail_path))
|
||||
{
|
||||
$thumbnail_deleted[] = $row['attach_id'];
|
||||
|
||||
if (count($thumbnail_deleted) === 250)
|
||||
{
|
||||
$this->commit_changes($thumbnail_deleted);
|
||||
$thumbnail_deleted = array();
|
||||
}
|
||||
|
||||
$progress->setMessage($this->user->lang('CLI_THUMBNAIL_DELETED', $row['real_filename'], $row['physical_filename']));
|
||||
}
|
||||
else
|
||||
{
|
||||
$return = 1;
|
||||
$progress->setMessage('<error>' . $this->user->lang('CLI_THUMBNAIL_SKIPPED', $row['real_filename'], $row['physical_filename']) . '</error>');
|
||||
}
|
||||
|
||||
$progress->advance();
|
||||
}
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
if (!empty($thumbnail_deleted))
|
||||
{
|
||||
$this->commit_changes($thumbnail_deleted);
|
||||
}
|
||||
|
||||
$progress->finish();
|
||||
|
||||
$io->newLine(2);
|
||||
$io->success($this->user->lang('CLI_THUMBNAIL_DELETING_DONE'));
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Commits the changes to the database
|
||||
*
|
||||
* @param array $thumbnail_deleted
|
||||
*/
|
||||
protected function commit_changes(array $thumbnail_deleted)
|
||||
{
|
||||
$sql = 'UPDATE ' . ATTACHMENTS_TABLE . '
|
||||
SET thumbnail = 0
|
||||
WHERE ' . $this->db->sql_in_set('attach_id', $thumbnail_deleted);
|
||||
$this->db->sql_query($sql);
|
||||
}
|
||||
}
|
||||
186
phpbb/console/command/thumbnail/generate.php
Normal file
186
phpbb/console/command/thumbnail/generate.php
Normal file
@@ -0,0 +1,186 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\console\command\thumbnail;
|
||||
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
class generate extends \phpbb\console\command\command
|
||||
{
|
||||
/**
|
||||
* @var \phpbb\config\config
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* @var \phpbb\db\driver\driver_interface
|
||||
*/
|
||||
protected $db;
|
||||
|
||||
/**
|
||||
* @var \phpbb\cache\service
|
||||
*/
|
||||
protected $cache;
|
||||
|
||||
/**
|
||||
* phpBB root path
|
||||
* @var string
|
||||
*/
|
||||
protected $phpbb_root_path;
|
||||
|
||||
/**
|
||||
* PHP extension.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $php_ext;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \config\config $config The config
|
||||
* @param \phpbb\user $user The user object (used to get language information)
|
||||
* @param \phpbb\db\driver\driver_interface $db Database connection
|
||||
* @param \phpbb\cache\service $cache The cache service
|
||||
* @param string $phpbb_root_path Root path
|
||||
* @param string $php_ext PHP extension
|
||||
*/
|
||||
public function __construct(\phpbb\config\config $config, \phpbb\user $user, \phpbb\db\driver\driver_interface $db, \phpbb\cache\service $cache, $phpbb_root_path, $php_ext)
|
||||
{
|
||||
$this->config = $config;
|
||||
$this->db = $db;
|
||||
$this->cache = $cache;
|
||||
$this->phpbb_root_path = $phpbb_root_path;
|
||||
$this->php_ext = $php_ext;
|
||||
|
||||
parent::__construct($user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the command name and description
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('thumbnail:generate')
|
||||
->setDescription($this->user->lang('CLI_DESCRIPTION_THUMBNAIL_GENERATE'))
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the command thumbnail:generate.
|
||||
*
|
||||
* Generate a thumbnail for all attachments which need one and don't have it yet.
|
||||
*
|
||||
* @param InputInterface $input The input stream used to get the argument and verboe option.
|
||||
* @param OutputInterface $output The output stream, used for printing verbose-mode and error information.
|
||||
*
|
||||
* @return int 0.
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
$io->section($this->user->lang('CLI_THUMBNAIL_GENERATING'));
|
||||
|
||||
$sql = 'SELECT COUNT(*) AS nb_missing_thumbnails
|
||||
FROM ' . ATTACHMENTS_TABLE . '
|
||||
WHERE thumbnail = 0';
|
||||
$result = $this->db->sql_query($sql);
|
||||
$nb_missing_thumbnails = (int) $this->db->sql_fetchfield('nb_missing_thumbnails');
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
if ($nb_missing_thumbnails === 0)
|
||||
{
|
||||
$io->warning($this->user->lang('CLI_THUMBNAIL_NOTHING_TO_GENERATE'));
|
||||
return 0;
|
||||
}
|
||||
|
||||
$extensions = $this->cache->obtain_attach_extensions(true);
|
||||
|
||||
$sql = 'SELECT attach_id, physical_filename, extension, real_filename, mimetype
|
||||
FROM ' . ATTACHMENTS_TABLE . '
|
||||
WHERE thumbnail = 0';
|
||||
$result = $this->db->sql_query($sql);
|
||||
|
||||
if (!function_exists('create_thumbnail'))
|
||||
{
|
||||
require($this->phpbb_root_path . 'includes/functions_posting.' . $this->php_ext);
|
||||
}
|
||||
|
||||
$progress = $this->create_progress_bar($nb_missing_thumbnails, $io, $output);
|
||||
|
||||
$progress->setMessage($this->user->lang('CLI_THUMBNAIL_GENERATING'));
|
||||
|
||||
$progress->start();
|
||||
|
||||
$thumbnail_created = array();
|
||||
while ($row = $this->db->sql_fetchrow($result))
|
||||
{
|
||||
if (isset($extensions[$row['extension']]['display_cat']) && $extensions[$row['extension']]['display_cat'] == ATTACHMENT_CATEGORY_IMAGE)
|
||||
{
|
||||
$source = $this->phpbb_root_path . $this->config['upload_path'] . '/' . $row['physical_filename'];
|
||||
$destination = $this->phpbb_root_path . $this->config['upload_path'] . '/thumb_' . $row['physical_filename'];
|
||||
|
||||
if (create_thumbnail($source, $destination, $row['mimetype']))
|
||||
{
|
||||
$thumbnail_created[] = (int) $row['attach_id'];
|
||||
|
||||
if (count($thumbnail_created) === 250)
|
||||
{
|
||||
$this->commit_changes($thumbnail_created);
|
||||
$thumbnail_created = array();
|
||||
}
|
||||
|
||||
$progress->setMessage($this->user->lang('CLI_THUMBNAIL_GENERATED', $row['real_filename'], $row['physical_filename']));
|
||||
}
|
||||
else
|
||||
{
|
||||
$progress->setMessage('<info>' . $this->user->lang('CLI_THUMBNAIL_SKIPPED', $row['real_filename'], $row['physical_filename']) . '</info>');
|
||||
}
|
||||
}
|
||||
|
||||
$progress->advance();
|
||||
}
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
if (!empty($thumbnail_created))
|
||||
{
|
||||
$this->commit_changes($thumbnail_created);
|
||||
}
|
||||
|
||||
$progress->finish();
|
||||
|
||||
$io->newLine(2);
|
||||
$io->success($this->user->lang('CLI_THUMBNAIL_GENERATING_DONE'));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Commits the changes to the database
|
||||
*
|
||||
* @param array $thumbnail_created
|
||||
*/
|
||||
protected function commit_changes(array $thumbnail_created)
|
||||
{
|
||||
$sql = 'UPDATE ' . ATTACHMENTS_TABLE . '
|
||||
SET thumbnail = 1
|
||||
WHERE ' . $this->db->sql_in_set('attach_id', $thumbnail_created);
|
||||
$this->db->sql_query($sql);
|
||||
}
|
||||
}
|
||||
72
phpbb/console/command/thumbnail/recreate.php
Normal file
72
phpbb/console/command/thumbnail/recreate.php
Normal file
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
namespace phpbb\console\command\thumbnail;
|
||||
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\ArrayInput;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class recreate extends \phpbb\console\command\command
|
||||
{
|
||||
/**
|
||||
* Sets the command name and description
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('thumbnail:recreate')
|
||||
->setDescription($this->user->lang('CLI_DESCRIPTION_THUMBNAIL_RECREATE'))
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the command thumbnail:recreate.
|
||||
*
|
||||
* This command is a "macro" to execute thumbnail:delete and then thumbnail:generate.
|
||||
*
|
||||
* @param InputInterface $input The input stream used to get the argument and verboe option.
|
||||
* @param OutputInterface $output The output stream, used for printing verbose-mode and error information.
|
||||
*
|
||||
* @return int 0 if all is ok, 1 if a thumbnail couldn't be deleted.
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$parameters = array(
|
||||
'command' => 'thumbnail:delete'
|
||||
);
|
||||
|
||||
if ($input->getOption('verbose'))
|
||||
{
|
||||
$parameters['-' . str_repeat('v', $output->getVerbosity() - 1)] = true;
|
||||
}
|
||||
|
||||
$this->getApplication()->setAutoExit(false);
|
||||
|
||||
$input_delete = new ArrayInput($parameters);
|
||||
$return = $this->getApplication()->run($input_delete, $output);
|
||||
|
||||
if ($return === 0)
|
||||
{
|
||||
$parameters['command'] = 'thumbnail:generate';
|
||||
|
||||
$input_create = new ArrayInput($parameters);
|
||||
$return = $this->getApplication()->run($input_create, $output);
|
||||
}
|
||||
|
||||
$this->getApplication()->setAutoExit(true);
|
||||
|
||||
return $return;
|
||||
}
|
||||
}
|
||||
331
phpbb/console/command/update/check.php
Normal file
331
phpbb/console/command/update/check.php
Normal file
@@ -0,0 +1,331 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\console\command\update;
|
||||
|
||||
use phpbb\config\config;
|
||||
use phpbb\exception\exception_interface;
|
||||
use phpbb\language\language;
|
||||
use phpbb\user;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
class check extends \phpbb\console\command\command
|
||||
{
|
||||
/** @var \phpbb\config\config */
|
||||
protected $config;
|
||||
|
||||
/** @var \Symfony\Component\DependencyInjection\ContainerBuilder */
|
||||
protected $phpbb_container;
|
||||
/**
|
||||
* @var language
|
||||
*/
|
||||
private $language;
|
||||
|
||||
/**
|
||||
* Construct method
|
||||
*/
|
||||
public function __construct(user $user, config $config, ContainerInterface $phpbb_container, language $language)
|
||||
{
|
||||
$this->config = $config;
|
||||
$this->phpbb_container = $phpbb_container;
|
||||
$this->language = $language;
|
||||
|
||||
$this->language->add_lang(array('acp/common', 'acp/extensions'));
|
||||
|
||||
parent::__construct($user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the service.
|
||||
*
|
||||
* Sets the name and description of the command.
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('update:check')
|
||||
->setDescription($this->language->lang('CLI_DESCRIPTION_UPDATE_CHECK'))
|
||||
->addArgument('ext-name', InputArgument::OPTIONAL, $this->language->lang('CLI_DESCRIPTION_UPDATE_CHECK_ARGUMENT_1'))
|
||||
->addOption('stability', null, InputOption::VALUE_REQUIRED, $this->language->lang('CLI_DESCRIPTION_UPDATE_CHECK_OPTION_STABILITY'))
|
||||
->addOption('cache', 'c', InputOption::VALUE_NONE, $this->language->lang('CLI_DESCRIPTION_UPDATE_CHECK_OPTION_CACHE'))
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the command.
|
||||
*
|
||||
* Checks if an update is available.
|
||||
* If at least one is available, a message is printed and if verbose mode is set the list of possible updates is printed.
|
||||
* If their is none, nothing is printed unless verbose mode is set.
|
||||
*
|
||||
* @param InputInterface $input Input stream, used to get the options.
|
||||
* @param OutputInterface $output Output stream, used to print messages.
|
||||
* @return int 0 if the board is up to date, 1 if it is not and 2 if an error occured.
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
$recheck = true;
|
||||
if ($input->getOption('cache'))
|
||||
{
|
||||
$recheck = false;
|
||||
}
|
||||
|
||||
$stability = null;
|
||||
if ($input->getOption('stability'))
|
||||
{
|
||||
$stability = $input->getOption('stability');
|
||||
if (!($stability == 'stable') && !($stability == 'unstable'))
|
||||
{
|
||||
$io->error($this->language->lang('CLI_ERROR_INVALID_STABILITY', $stability));
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
|
||||
$ext_name = $input->getArgument('ext-name');
|
||||
if ($ext_name != null)
|
||||
{
|
||||
if ($ext_name == 'all')
|
||||
{
|
||||
return $this->check_all_ext($io, $stability, $recheck);
|
||||
}
|
||||
else
|
||||
{
|
||||
return $this->check_ext($input, $io, $stability, $recheck, $ext_name);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return $this->check_core($input, $io, $stability, $recheck);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given extension is up to date
|
||||
*
|
||||
* @param InputInterface $input Input stream, used to get the options.
|
||||
* @param SymfonyStyle $io IO handler, for formatted and unified IO
|
||||
* @param string $stability Force a given stability
|
||||
* @param bool $recheck Disallow the use of the cache
|
||||
* @param string $ext_name The extension name
|
||||
* @return int
|
||||
*/
|
||||
protected function check_ext(InputInterface $input, SymfonyStyle $io, $stability, $recheck, $ext_name)
|
||||
{
|
||||
try
|
||||
{
|
||||
$ext_manager = $this->phpbb_container->get('ext.manager');
|
||||
$md_manager = $ext_manager->create_extension_metadata_manager($ext_name);
|
||||
$updates_available = $ext_manager->version_check($md_manager, $recheck, false, $stability);
|
||||
|
||||
$metadata = $md_manager->get_metadata('all');
|
||||
if ($input->getOption('verbose'))
|
||||
{
|
||||
$io->title($md_manager->get_metadata('display-name'));
|
||||
|
||||
$io->note($this->language->lang('CURRENT_VERSION') . $this->language->lang('COLON') . ' ' . $metadata['version']);
|
||||
}
|
||||
|
||||
if (!empty($updates_available))
|
||||
{
|
||||
if ($input->getOption('verbose'))
|
||||
{
|
||||
$io->caution($this->language->lang('NOT_UP_TO_DATE', $metadata['name']));
|
||||
|
||||
$this->display_versions($io, $updates_available);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($input->getOption('verbose'))
|
||||
{
|
||||
$io->success($this->language->lang('UPDATE_NOT_NEEDED'));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
catch (\RuntimeException $e)
|
||||
{
|
||||
$io->error($this->language->lang('EXTENSION_NOT_INSTALLED', $ext_name));
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the core is up to date
|
||||
*
|
||||
* @param InputInterface $input Input stream, used to get the options.
|
||||
* @param SymfonyStyle $io IO handler, for formatted and unified IO
|
||||
* @param string $stability Force a given stability
|
||||
* @param bool $recheck Disallow the use of the cache
|
||||
* @return int
|
||||
*/
|
||||
protected function check_core(InputInterface $input, SymfonyStyle $io, $stability, $recheck)
|
||||
{
|
||||
$version_helper = $this->phpbb_container->get('version_helper');
|
||||
$version_helper->force_stability($stability);
|
||||
|
||||
$updates_available = $version_helper->get_suggested_updates($recheck);
|
||||
|
||||
if ($input->getOption('verbose'))
|
||||
{
|
||||
$io->title('phpBB core');
|
||||
|
||||
$io->note( $this->language->lang('CURRENT_VERSION') . $this->language->lang('COLON') . ' ' . $this->config['version']);
|
||||
}
|
||||
|
||||
if (!empty($updates_available))
|
||||
{
|
||||
$io->caution($this->language->lang('UPDATE_NEEDED'));
|
||||
|
||||
if ($input->getOption('verbose'))
|
||||
{
|
||||
$this->display_versions($io, $updates_available);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($input->getOption('verbose'))
|
||||
{
|
||||
$io->success($this->language->lang('UPDATE_NOT_NEEDED'));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if all the available extensions are up to date
|
||||
*
|
||||
* @param SymfonyStyle $io IO handler, for formatted and unified IO
|
||||
* @param bool $recheck Disallow the use of the cache
|
||||
* @return int
|
||||
*/
|
||||
protected function check_all_ext(SymfonyStyle $io, $stability, $recheck)
|
||||
{
|
||||
/** @var \phpbb\extension\manager $ext_manager */
|
||||
$ext_manager = $this->phpbb_container->get('ext.manager');
|
||||
|
||||
$rows = [];
|
||||
|
||||
foreach ($ext_manager->all_available() as $ext_name => $ext_path)
|
||||
{
|
||||
$row = [];
|
||||
$row[] = sprintf("<info>%s</info>", $ext_name);
|
||||
$md_manager = $ext_manager->create_extension_metadata_manager($ext_name);
|
||||
try
|
||||
{
|
||||
$metadata = $md_manager->get_metadata('all');
|
||||
if (isset($metadata['extra']['version-check']))
|
||||
{
|
||||
try {
|
||||
$updates_available = $ext_manager->version_check($md_manager, $recheck, false, $stability);
|
||||
if (!empty($updates_available))
|
||||
{
|
||||
$versions = array_map(function($entry)
|
||||
{
|
||||
return $entry['current'];
|
||||
}, $updates_available);
|
||||
|
||||
$row[] = sprintf("<comment>%s</comment>", $metadata['version']);
|
||||
$row[] = implode(', ', $versions);
|
||||
}
|
||||
else
|
||||
{
|
||||
$row[] = sprintf("<info>%s</info>", $metadata['version']);
|
||||
$row[] = '';
|
||||
}
|
||||
} catch (\RuntimeException $e) {
|
||||
$row[] = $metadata['version'];
|
||||
$row[] = '';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$row[] = $metadata['version'];
|
||||
$row[] = '';
|
||||
}
|
||||
}
|
||||
catch (exception_interface $e)
|
||||
{
|
||||
$exception_message = call_user_func_array(array($this->user, 'lang'), array_merge(array($e->getMessage()), $e->get_parameters()));
|
||||
$row[] = '<error>' . $exception_message . '</error>';
|
||||
}
|
||||
catch (\RuntimeException $e)
|
||||
{
|
||||
$row[] = '<error>' . $e->getMessage() . '</error>';
|
||||
}
|
||||
|
||||
$rows[] = $row;
|
||||
}
|
||||
|
||||
$io->table([
|
||||
$this->language->lang('EXTENSION_NAME'),
|
||||
$this->language->lang('CURRENT_VERSION'),
|
||||
$this->language->lang('LATEST_VERSION'),
|
||||
], $rows);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the details of the available updates
|
||||
*
|
||||
* @param SymfonyStyle $io IO handler, for formatted and unified IO
|
||||
* @param array $updates_available The list of the available updates
|
||||
*/
|
||||
protected function display_versions(SymfonyStyle $io, $updates_available)
|
||||
{
|
||||
$io->section($this->language->lang('UPDATES_AVAILABLE'));
|
||||
|
||||
$rows = [];
|
||||
foreach ($updates_available as $version_data)
|
||||
{
|
||||
$row = ['', '', ''];
|
||||
$row[0] = $version_data['current'];
|
||||
|
||||
if (isset($version_data['announcement']))
|
||||
{
|
||||
$row[1] = $version_data['announcement'];
|
||||
}
|
||||
|
||||
if (isset($version_data['download']))
|
||||
{
|
||||
$row[2] = $version_data['download'];
|
||||
}
|
||||
|
||||
$rows[] = $row;
|
||||
}
|
||||
|
||||
$io->table([
|
||||
$this->language->lang('VERSION'),
|
||||
$this->language->lang('ANNOUNCEMENT_TOPIC'),
|
||||
$this->language->lang('DOWNLOAD_LATEST'),
|
||||
], $rows);
|
||||
}
|
||||
}
|
||||
218
phpbb/console/command/user/activate.php
Normal file
218
phpbb/console/command/user/activate.php
Normal file
@@ -0,0 +1,218 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\console\command\user;
|
||||
|
||||
use phpbb\config\config;
|
||||
use phpbb\console\command\command;
|
||||
use phpbb\db\driver\driver_interface;
|
||||
use phpbb\language\language;
|
||||
use phpbb\log\log_interface;
|
||||
use phpbb\notification\manager;
|
||||
use phpbb\user;
|
||||
use phpbb\user_loader;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
class activate extends command
|
||||
{
|
||||
/** @var driver_interface */
|
||||
protected $db;
|
||||
|
||||
/** @var config */
|
||||
protected $config;
|
||||
|
||||
/** @var language */
|
||||
protected $language;
|
||||
|
||||
/** @var log_interface */
|
||||
protected $log;
|
||||
|
||||
/** @var manager */
|
||||
protected $notifications;
|
||||
|
||||
/** @var user_loader */
|
||||
protected $user_loader;
|
||||
|
||||
/**
|
||||
* phpBB root path
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $phpbb_root_path;
|
||||
|
||||
/**
|
||||
* PHP extension.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $php_ext;
|
||||
|
||||
/**
|
||||
* Construct method
|
||||
*
|
||||
* @param user $user
|
||||
* @param driver_interface $db
|
||||
* @param config $config
|
||||
* @param language $language
|
||||
* @param log_interface $log
|
||||
* @param manager $notifications
|
||||
* @param user_loader $user_loader
|
||||
* @param string $phpbb_root_path
|
||||
* @param string $php_ext
|
||||
*/
|
||||
public function __construct(user $user, driver_interface $db, config $config, language $language, log_interface $log, manager $notifications, user_loader $user_loader, $phpbb_root_path, $php_ext)
|
||||
{
|
||||
$this->db = $db;
|
||||
$this->config = $config;
|
||||
$this->language = $language;
|
||||
$this->log = $log;
|
||||
$this->notifications = $notifications;
|
||||
$this->user_loader = $user_loader;
|
||||
$this->phpbb_root_path = $phpbb_root_path;
|
||||
$this->php_ext = $php_ext;
|
||||
|
||||
$this->language->add_lang('acp/users');
|
||||
parent::__construct($user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the command name and description
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('user:activate')
|
||||
->setDescription($this->language->lang('CLI_DESCRIPTION_USER_ACTIVATE'))
|
||||
->setHelp($this->language->lang('CLI_HELP_USER_ACTIVATE'))
|
||||
->addArgument(
|
||||
'username',
|
||||
InputArgument::REQUIRED,
|
||||
$this->language->lang('CLI_DESCRIPTION_USER_ACTIVATE_USERNAME')
|
||||
)
|
||||
->addOption(
|
||||
'deactivate',
|
||||
'd',
|
||||
InputOption::VALUE_NONE,
|
||||
$this->language->lang('CLI_DESCRIPTION_USER_ACTIVATE_DEACTIVATE')
|
||||
)
|
||||
->addOption(
|
||||
'send-email',
|
||||
null,
|
||||
InputOption::VALUE_NONE,
|
||||
$this->language->lang('CLI_DESCRIPTION_USER_ADD_OPTION_NOTIFY')
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the command user:activate
|
||||
*
|
||||
* Activate (or deactivate) a user account
|
||||
*
|
||||
* @param InputInterface $input The input stream used to get the options
|
||||
* @param OutputInterface $output The output stream, used to print messages
|
||||
*
|
||||
* @return int 0 if all is well, 1 if any errors occurred
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
$name = $input->getArgument('username');
|
||||
$mode = ($input->getOption('deactivate')) ? 'deactivate' : 'activate';
|
||||
|
||||
$user_id = $this->user_loader->load_user_by_username($name);
|
||||
$user_row = $this->user_loader->get_user($user_id);
|
||||
|
||||
if ($user_row['user_id'] == ANONYMOUS)
|
||||
{
|
||||
$io->error($this->language->lang('NO_USER'));
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Check if the user is already active (or inactive)
|
||||
if ($mode == 'activate' && $user_row['user_type'] != USER_INACTIVE)
|
||||
{
|
||||
$io->error($this->language->lang('CLI_DESCRIPTION_USER_ACTIVATE_ACTIVE'));
|
||||
return 1;
|
||||
}
|
||||
else if ($mode == 'deactivate' && $user_row['user_type'] == USER_INACTIVE)
|
||||
{
|
||||
$io->error($this->language->lang('CLI_DESCRIPTION_USER_ACTIVATE_INACTIVE'));
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Activate the user account
|
||||
if (!function_exists('user_active_flip'))
|
||||
{
|
||||
require($this->phpbb_root_path . 'includes/functions_user.' . $this->php_ext);
|
||||
}
|
||||
|
||||
user_active_flip($mode, $user_row['user_id']);
|
||||
|
||||
// Notify the user upon activation
|
||||
if ($mode == 'activate' && $this->config['require_activation'] == USER_ACTIVATION_ADMIN)
|
||||
{
|
||||
$this->send_notification($user_row, $input);
|
||||
}
|
||||
|
||||
// Log and display the result
|
||||
$msg = ($mode == 'activate') ? 'USER_ADMIN_ACTIVATED' : 'USER_ADMIN_DEACTIVED';
|
||||
$log = ($mode == 'activate') ? 'LOG_USER_ACTIVE' : 'LOG_USER_INACTIVE';
|
||||
|
||||
$this->log->add('admin', ANONYMOUS, '', $log, false, array($user_row['username']));
|
||||
$this->log->add('user', ANONYMOUS, '', $log . '_USER', false, array(
|
||||
'reportee_id' => $user_row['user_id']
|
||||
));
|
||||
|
||||
$io->success($this->language->lang($msg));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send account activation notification to user
|
||||
*
|
||||
* @param array $user_row The user data array
|
||||
* @param InputInterface $input The input stream used to get the options
|
||||
* @return null
|
||||
*/
|
||||
protected function send_notification($user_row, InputInterface $input)
|
||||
{
|
||||
$this->notifications->delete_notifications('notification.type.admin_activate_user', $user_row['user_id']);
|
||||
|
||||
if ($input->getOption('send-email'))
|
||||
{
|
||||
if (!class_exists('messenger'))
|
||||
{
|
||||
require($this->phpbb_root_path . 'includes/functions_messenger.' . $this->php_ext);
|
||||
}
|
||||
|
||||
$messenger = new \messenger(false);
|
||||
$messenger->template('admin_welcome_activated', $user_row['user_lang']);
|
||||
$messenger->set_addresses($user_row);
|
||||
$messenger->anti_abuse_headers($this->config, $this->user);
|
||||
$messenger->assign_vars(array(
|
||||
'USERNAME' => htmlspecialchars_decode($user_row['username']))
|
||||
);
|
||||
|
||||
$messenger->send(NOTIFY_EMAIL);
|
||||
}
|
||||
}
|
||||
}
|
||||
334
phpbb/console/command/user/add.php
Normal file
334
phpbb/console/command/user/add.php
Normal file
@@ -0,0 +1,334 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\console\command\user;
|
||||
|
||||
use phpbb\config\config;
|
||||
use phpbb\console\command\command;
|
||||
use phpbb\db\driver\driver_interface;
|
||||
use phpbb\exception\runtime_exception;
|
||||
use phpbb\language\language;
|
||||
use phpbb\passwords\manager;
|
||||
use phpbb\user;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Question\Question;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
class add extends command
|
||||
{
|
||||
/** @var array Array of interactively acquired options */
|
||||
protected $data;
|
||||
|
||||
/** @var driver_interface */
|
||||
protected $db;
|
||||
|
||||
/** @var config */
|
||||
protected $config;
|
||||
|
||||
/** @var language */
|
||||
protected $language;
|
||||
|
||||
/** @var manager */
|
||||
protected $password_manager;
|
||||
|
||||
/**
|
||||
* phpBB root path
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $phpbb_root_path;
|
||||
|
||||
/**
|
||||
* PHP extension.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $php_ext;
|
||||
|
||||
/**
|
||||
* Construct method
|
||||
*
|
||||
* @param user $user
|
||||
* @param driver_interface $db
|
||||
* @param config $config
|
||||
* @param language $language
|
||||
* @param manager $password_manager
|
||||
* @param string $phpbb_root_path
|
||||
* @param string $php_ext
|
||||
*/
|
||||
public function __construct(user $user, driver_interface $db, config $config, language $language, manager $password_manager, $phpbb_root_path, $php_ext)
|
||||
{
|
||||
$this->db = $db;
|
||||
$this->config = $config;
|
||||
$this->language = $language;
|
||||
$this->password_manager = $password_manager;
|
||||
$this->phpbb_root_path = $phpbb_root_path;
|
||||
$this->php_ext = $php_ext;
|
||||
|
||||
$this->language->add_lang('ucp');
|
||||
parent::__construct($user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the command name and description
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('user:add')
|
||||
->setDescription($this->language->lang('CLI_DESCRIPTION_USER_ADD'))
|
||||
->setHelp($this->language->lang('CLI_HELP_USER_ADD'))
|
||||
->addOption(
|
||||
'username',
|
||||
'U',
|
||||
InputOption::VALUE_REQUIRED,
|
||||
$this->language->lang('CLI_DESCRIPTION_USER_ADD_OPTION_USERNAME')
|
||||
)
|
||||
->addOption(
|
||||
'password',
|
||||
'P',
|
||||
InputOption::VALUE_REQUIRED,
|
||||
$this->language->lang('CLI_DESCRIPTION_USER_ADD_OPTION_PASSWORD')
|
||||
)
|
||||
->addOption(
|
||||
'email',
|
||||
'E',
|
||||
InputOption::VALUE_REQUIRED,
|
||||
$this->language->lang('CLI_DESCRIPTION_USER_ADD_OPTION_EMAIL')
|
||||
)
|
||||
->addOption(
|
||||
'send-email',
|
||||
null,
|
||||
InputOption::VALUE_NONE,
|
||||
$this->language->lang('CLI_DESCRIPTION_USER_ADD_OPTION_NOTIFY')
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the command user:add
|
||||
*
|
||||
* Adds a new user to the database. If options are not provided, it will ask for the username, password and email.
|
||||
* User is added to the registered user group. Language and timezone default to $config settings.
|
||||
*
|
||||
* @param InputInterface $input The input stream used to get the options
|
||||
* @param OutputInterface $output The output stream, used to print messages
|
||||
*
|
||||
* @return int 0 if all is well, 1 if any errors occurred
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
try
|
||||
{
|
||||
$this->validate_user_data();
|
||||
$group_id = $this->get_group_id();
|
||||
}
|
||||
catch (runtime_exception $e)
|
||||
{
|
||||
$io->error($e->getMessage());
|
||||
return 1;
|
||||
}
|
||||
|
||||
$user_row = array(
|
||||
'username' => $this->data['username'],
|
||||
'user_password' => $this->password_manager->hash($this->data['new_password']),
|
||||
'user_email' => $this->data['email'],
|
||||
'group_id' => $group_id,
|
||||
'user_timezone' => $this->config['board_timezone'],
|
||||
'user_lang' => $this->config['default_lang'],
|
||||
'user_type' => USER_NORMAL,
|
||||
'user_regdate' => time(),
|
||||
);
|
||||
|
||||
$user_id = (int) user_add($user_row);
|
||||
|
||||
if (!$user_id)
|
||||
{
|
||||
$io->error($this->language->lang('AUTH_NO_PROFILE_CREATED'));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ($input->getOption('send-email') && $this->config['email_enable'])
|
||||
{
|
||||
$this->send_activation_email($user_id);
|
||||
}
|
||||
|
||||
$io->success($this->language->lang('CLI_USER_ADD_SUCCESS', $this->data['username']));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interacts with the user.
|
||||
*
|
||||
* @param InputInterface $input An InputInterface instance
|
||||
* @param OutputInterface $output An OutputInterface instance
|
||||
*/
|
||||
protected function interact(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$helper = $this->getHelper('question');
|
||||
|
||||
$this->data = array(
|
||||
'username' => $input->getOption('username'),
|
||||
'new_password' => $input->getOption('password'),
|
||||
'email' => $input->getOption('email'),
|
||||
);
|
||||
|
||||
if (!$this->data['username'])
|
||||
{
|
||||
$question = new Question($this->ask_user('USERNAME'));
|
||||
$this->data['username'] = $helper->ask($input, $output, $question);
|
||||
}
|
||||
|
||||
if (!$this->data['new_password'])
|
||||
{
|
||||
$question = new Question($this->ask_user('PASSWORD'));
|
||||
$question->setValidator(function ($value) use ($helper, $input, $output) {
|
||||
$question = new Question($this->ask_user('CONFIRM_PASSWORD'));
|
||||
$question->setHidden(true);
|
||||
if ($helper->ask($input, $output, $question) != $value)
|
||||
{
|
||||
throw new runtime_exception($this->language->lang('NEW_PASSWORD_ERROR'));
|
||||
}
|
||||
return $value;
|
||||
});
|
||||
$question->setHidden(true);
|
||||
$question->setMaxAttempts(5);
|
||||
|
||||
$this->data['new_password'] = $helper->ask($input, $output, $question);
|
||||
}
|
||||
|
||||
if (!$this->data['email'])
|
||||
{
|
||||
$question = new Question($this->ask_user('EMAIL_ADDRESS'));
|
||||
$this->data['email'] = $helper->ask($input, $output, $question);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the submitted user data
|
||||
*
|
||||
* @throws runtime_exception if any data fails validation
|
||||
* @return null
|
||||
*/
|
||||
protected function validate_user_data()
|
||||
{
|
||||
if (!function_exists('validate_data'))
|
||||
{
|
||||
require($this->phpbb_root_path . 'includes/functions_user.' . $this->php_ext);
|
||||
}
|
||||
|
||||
$error = validate_data($this->data, array(
|
||||
'username' => array(
|
||||
array('string', false, $this->config['min_name_chars'], $this->config['max_name_chars']),
|
||||
array('username', '')),
|
||||
'new_password' => array(
|
||||
array('string', false, $this->config['min_pass_chars'], $this->config['max_pass_chars']),
|
||||
array('password')),
|
||||
'email' => array(
|
||||
array('string', false, 6, 60),
|
||||
array('user_email')),
|
||||
));
|
||||
|
||||
if ($error)
|
||||
{
|
||||
throw new runtime_exception(implode("\n", array_map(array($this->language, 'lang'), $error)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the group id
|
||||
*
|
||||
* Go and find in the database the group_id corresponding to 'REGISTERED'
|
||||
*
|
||||
* @throws runtime_exception if the group id does not exist in database.
|
||||
* @return null
|
||||
*/
|
||||
protected function get_group_id()
|
||||
{
|
||||
$sql = 'SELECT group_id
|
||||
FROM ' . GROUPS_TABLE . "
|
||||
WHERE group_name = '" . $this->db->sql_escape('REGISTERED') . "'
|
||||
AND group_type = " . GROUP_SPECIAL;
|
||||
$result = $this->db->sql_query($sql);
|
||||
$row = $this->db->sql_fetchrow($result);
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
if (!$row || !$row['group_id'])
|
||||
{
|
||||
throw new runtime_exception($this->language->lang('NO_GROUP'));
|
||||
}
|
||||
|
||||
return $row['group_id'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Send account activation email
|
||||
*
|
||||
* @param int $user_id The new user's id
|
||||
* @return null
|
||||
*/
|
||||
protected function send_activation_email($user_id)
|
||||
{
|
||||
switch ($this->config['require_activation'])
|
||||
{
|
||||
case USER_ACTIVATION_SELF:
|
||||
$email_template = 'user_welcome_inactive';
|
||||
$user_actkey = gen_rand_string(mt_rand(6, 10));
|
||||
break;
|
||||
case USER_ACTIVATION_ADMIN:
|
||||
$email_template = 'admin_welcome_inactive';
|
||||
$user_actkey = gen_rand_string(mt_rand(6, 10));
|
||||
break;
|
||||
default:
|
||||
$email_template = 'user_welcome';
|
||||
$user_actkey = '';
|
||||
break;
|
||||
}
|
||||
|
||||
if (!class_exists('messenger'))
|
||||
{
|
||||
require($this->phpbb_root_path . 'includes/functions_messenger.' . $this->php_ext);
|
||||
}
|
||||
|
||||
$messenger = new \messenger(false);
|
||||
$messenger->template($email_template, $this->user->lang_name);
|
||||
$messenger->to($this->data['email'], $this->data['username']);
|
||||
$messenger->anti_abuse_headers($this->config, $this->user);
|
||||
$messenger->assign_vars(array(
|
||||
'WELCOME_MSG' => htmlspecialchars_decode($this->language->lang('WELCOME_SUBJECT', $this->config['sitename'])),
|
||||
'USERNAME' => htmlspecialchars_decode($this->data['username']),
|
||||
'PASSWORD' => htmlspecialchars_decode($this->data['new_password']),
|
||||
'U_ACTIVATE' => generate_board_url() . "/ucp.{$this->php_ext}?mode=activate&u=$user_id&k=$user_actkey")
|
||||
);
|
||||
|
||||
$messenger->send(NOTIFY_EMAIL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to translate questions to the user
|
||||
*
|
||||
* @param string $key The language key
|
||||
* @return string The language key translated with a colon and space appended
|
||||
*/
|
||||
protected function ask_user($key)
|
||||
{
|
||||
return $this->language->lang($key) . $this->language->lang('COLON') . ' ';
|
||||
}
|
||||
}
|
||||
170
phpbb/console/command/user/delete.php
Normal file
170
phpbb/console/command/user/delete.php
Normal file
@@ -0,0 +1,170 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\console\command\user;
|
||||
|
||||
use phpbb\console\command\command;
|
||||
use phpbb\db\driver\driver_interface;
|
||||
use phpbb\language\language;
|
||||
use phpbb\log\log_interface;
|
||||
use phpbb\user;
|
||||
use phpbb\user_loader;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Question\ConfirmationQuestion;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
class delete extends command
|
||||
{
|
||||
/** @var driver_interface */
|
||||
protected $db;
|
||||
|
||||
/** @var language */
|
||||
protected $language;
|
||||
|
||||
/** @var log_interface */
|
||||
protected $log;
|
||||
|
||||
/** @var user_loader */
|
||||
protected $user_loader;
|
||||
|
||||
/**
|
||||
* phpBB root path
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $phpbb_root_path;
|
||||
|
||||
/**
|
||||
* PHP extension.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $php_ext;
|
||||
|
||||
/**
|
||||
* Construct method
|
||||
*
|
||||
* @param user $user
|
||||
* @param driver_interface $db
|
||||
* @param language $language
|
||||
* @param log_interface $log
|
||||
* @param user_loader $user_loader
|
||||
* @param string $phpbb_root_path
|
||||
* @param string $php_ext
|
||||
*/
|
||||
public function __construct(user $user, driver_interface $db, language $language, log_interface $log, user_loader $user_loader, $phpbb_root_path, $php_ext)
|
||||
{
|
||||
$this->db = $db;
|
||||
$this->language = $language;
|
||||
$this->log = $log;
|
||||
$this->user_loader = $user_loader;
|
||||
$this->phpbb_root_path = $phpbb_root_path;
|
||||
$this->php_ext = $php_ext;
|
||||
|
||||
$this->language->add_lang('acp/users');
|
||||
parent::__construct($user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the command name and description
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('user:delete')
|
||||
->setDescription($this->language->lang('CLI_DESCRIPTION_USER_DELETE'))
|
||||
->addArgument(
|
||||
'username',
|
||||
InputArgument::REQUIRED,
|
||||
$this->language->lang('CLI_DESCRIPTION_USER_DELETE_USERNAME')
|
||||
)
|
||||
->addOption(
|
||||
'delete-posts',
|
||||
null,
|
||||
InputOption::VALUE_NONE,
|
||||
$this->language->lang('CLI_DESCRIPTION_USER_DELETE_OPTION_POSTS')
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the command user:delete
|
||||
*
|
||||
* Deletes a user from the database. An option to delete the user's posts
|
||||
* is available, by default posts will be retained.
|
||||
*
|
||||
* @param InputInterface $input The input stream used to get the options
|
||||
* @param OutputInterface $output The output stream, used to print messages
|
||||
*
|
||||
* @return int 0 if all is well, 1 if any errors occurred
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$name = $input->getArgument('username');
|
||||
$mode = ($input->getOption('delete-posts')) ? 'remove' : 'retain';
|
||||
|
||||
if ($name)
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
$user_id = $this->user_loader->load_user_by_username($name);
|
||||
$user_row = $this->user_loader->get_user($user_id);
|
||||
|
||||
if ($user_row['user_id'] == ANONYMOUS)
|
||||
{
|
||||
$io->error($this->language->lang('NO_USER'));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!function_exists('user_delete'))
|
||||
{
|
||||
require($this->phpbb_root_path . 'includes/functions_user.' . $this->php_ext);
|
||||
}
|
||||
|
||||
user_delete($mode, $user_row['user_id'], $user_row['username']);
|
||||
|
||||
$this->log->add('admin', ANONYMOUS, '', 'LOG_USER_DELETED', false, array($user_row['username']));
|
||||
|
||||
$io->success($this->language->lang('USER_DELETED'));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interacts with the user.
|
||||
* Confirm they really want to delete the account...last chance!
|
||||
*
|
||||
* @param InputInterface $input An InputInterface instance
|
||||
* @param OutputInterface $output An OutputInterface instance
|
||||
*/
|
||||
protected function interact(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$helper = $this->getHelper('question');
|
||||
|
||||
$question = new ConfirmationQuestion(
|
||||
$this->language->lang('CLI_USER_DELETE_CONFIRM', $input->getArgument('username')),
|
||||
false
|
||||
);
|
||||
|
||||
if (!$helper->ask($input, $output, $question))
|
||||
{
|
||||
$input->setArgument('username', false);
|
||||
}
|
||||
}
|
||||
}
|
||||
158
phpbb/console/command/user/reclean.php
Normal file
158
phpbb/console/command/user/reclean.php
Normal file
@@ -0,0 +1,158 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\console\command\user;
|
||||
|
||||
use phpbb\console\command\command;
|
||||
use phpbb\db\driver\driver_interface;
|
||||
use phpbb\language\language;
|
||||
use phpbb\user;
|
||||
use Symfony\Component\Console\Helper\ProgressBar;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
class reclean extends command
|
||||
{
|
||||
/** @var driver_interface */
|
||||
protected $db;
|
||||
|
||||
/** @var language */
|
||||
protected $language;
|
||||
|
||||
/** @var int A count of the number of re-cleaned user names */
|
||||
protected $processed;
|
||||
|
||||
/** @var ProgressBar */
|
||||
protected $progress;
|
||||
|
||||
/**
|
||||
* Construct method
|
||||
*
|
||||
* @param user $user
|
||||
* @param driver_interface $db
|
||||
* @param language $language
|
||||
*/
|
||||
public function __construct(user $user, driver_interface $db, language $language)
|
||||
{
|
||||
$this->db = $db;
|
||||
$this->language = $language;
|
||||
|
||||
parent::__construct($user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the command name and description
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('user:reclean')
|
||||
->setDescription($this->language->lang('CLI_DESCRIPTION_USER_RECLEAN'))
|
||||
->setHelp($this->language->lang('CLI_HELP_USER_RECLEAN'))
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the command user:reclean
|
||||
*
|
||||
* Cleans user names that are unclean.
|
||||
*
|
||||
* @param InputInterface $input The input stream used to get the options
|
||||
* @param OutputInterface $output The output stream, used to print messages
|
||||
*
|
||||
* @return int 0 if all is well, 1 if any errors occurred
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
$io->section($this->language->lang('CLI_USER_RECLEAN_START'));
|
||||
|
||||
$this->processed = 0;
|
||||
|
||||
$this->progress = $this->create_progress_bar($this->get_count(), $io, $output);
|
||||
$this->progress->setMessage($this->language->lang('CLI_USER_RECLEAN_START'));
|
||||
$this->progress->start();
|
||||
|
||||
$stage = 0;
|
||||
while ($stage !== true)
|
||||
{
|
||||
$stage = $this->reclean_usernames($stage);
|
||||
}
|
||||
|
||||
$this->progress->finish();
|
||||
|
||||
$io->newLine(2);
|
||||
$io->success($this->language->lang('CLI_USER_RECLEAN_DONE', $this->processed));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-clean user names
|
||||
* Only user names that are unclean will be re-cleaned
|
||||
*
|
||||
* @param int $start An offset index
|
||||
* @return bool|int Return the next offset index or true if all records have been processed.
|
||||
*/
|
||||
protected function reclean_usernames($start = 0)
|
||||
{
|
||||
$limit = 500;
|
||||
$i = 0;
|
||||
|
||||
$this->db->sql_transaction('begin');
|
||||
|
||||
$sql = 'SELECT user_id, username, username_clean FROM ' . USERS_TABLE;
|
||||
$result = $this->db->sql_query_limit($sql, $limit, $start);
|
||||
while ($row = $this->db->sql_fetchrow($result))
|
||||
{
|
||||
$i++;
|
||||
$username_clean = $this->db->sql_escape(utf8_clean_string($row['username']));
|
||||
|
||||
if ($username_clean != $row['username_clean'])
|
||||
{
|
||||
$sql = 'UPDATE ' . USERS_TABLE . "
|
||||
SET username_clean = '$username_clean'
|
||||
WHERE user_id = {$row['user_id']}";
|
||||
$this->db->sql_query($sql);
|
||||
|
||||
$this->processed++;
|
||||
}
|
||||
|
||||
$this->progress->advance();
|
||||
}
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
$this->db->sql_transaction('commit');
|
||||
|
||||
return ($i < $limit) ? true : $start + $i;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the count of users in the database
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function get_count()
|
||||
{
|
||||
$sql = 'SELECT COUNT(user_id) AS count FROM ' . USERS_TABLE;
|
||||
$result = $this->db->sql_query($sql);
|
||||
$count = (int) $this->db->sql_fetchfield('count');
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
return $count;
|
||||
}
|
||||
}
|
||||
65
phpbb/console/exception_subscriber.php
Normal file
65
phpbb/console/exception_subscriber.php
Normal file
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\console;
|
||||
|
||||
use phpbb\exception\exception_interface;
|
||||
use Symfony\Component\Console\ConsoleEvents;
|
||||
use Symfony\Component\Console\Event\ConsoleExceptionEvent;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
|
||||
class exception_subscriber implements EventSubscriberInterface
|
||||
{
|
||||
/**
|
||||
* @var \phpbb\language\language
|
||||
*/
|
||||
protected $language;
|
||||
|
||||
/**
|
||||
* Construct method
|
||||
*
|
||||
* @param \phpbb\language\language $language Language object
|
||||
*/
|
||||
public function __construct(\phpbb\language\language $language)
|
||||
{
|
||||
$this->language = $language;
|
||||
}
|
||||
|
||||
/**
|
||||
* This listener is run when the ConsoleEvents::EXCEPTION event is triggered.
|
||||
* It translate the exception message. If din debug mode the original exception is embedded.
|
||||
*
|
||||
* @param ConsoleExceptionEvent $event
|
||||
*/
|
||||
public function on_exception(ConsoleExceptionEvent $event)
|
||||
{
|
||||
$original_exception = $event->getException();
|
||||
|
||||
if ($original_exception instanceof exception_interface)
|
||||
{
|
||||
$parameters = array_merge(array($original_exception->getMessage()), $original_exception->get_parameters());
|
||||
$message = call_user_func_array(array($this->language, 'lang'), $parameters);
|
||||
|
||||
$exception = new \RuntimeException($message , $original_exception->getCode(), $original_exception);
|
||||
|
||||
$event->setException($exception);
|
||||
}
|
||||
}
|
||||
|
||||
static public function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
ConsoleEvents::EXCEPTION => 'on_exception',
|
||||
);
|
||||
}
|
||||
}
|
||||
885
phpbb/content_visibility.php
Normal file
885
phpbb/content_visibility.php
Normal file
@@ -0,0 +1,885 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb;
|
||||
|
||||
/**
|
||||
* phpbb_visibility
|
||||
* Handle fetching and setting the visibility for topics and posts
|
||||
*/
|
||||
class content_visibility
|
||||
{
|
||||
/**
|
||||
* Database object
|
||||
* @var \phpbb\db\driver\driver_interface
|
||||
*/
|
||||
protected $db;
|
||||
|
||||
/**
|
||||
* User object
|
||||
* @var \phpbb\user
|
||||
*/
|
||||
protected $user;
|
||||
|
||||
/**
|
||||
* Auth object
|
||||
* @var \phpbb\auth\auth
|
||||
*/
|
||||
protected $auth;
|
||||
|
||||
/**
|
||||
* config object
|
||||
* @var \phpbb\config\config
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* Event dispatcher object
|
||||
* @var \phpbb\event\dispatcher_interface
|
||||
*/
|
||||
protected $phpbb_dispatcher;
|
||||
|
||||
/**
|
||||
* phpBB root path
|
||||
* @var string
|
||||
*/
|
||||
protected $phpbb_root_path;
|
||||
|
||||
/**
|
||||
* PHP Extension
|
||||
* @var string
|
||||
*/
|
||||
protected $php_ext;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \phpbb\auth\auth $auth Auth object
|
||||
* @param \phpbb\config\config $config Config object
|
||||
* @param \phpbb\event\dispatcher_interface $phpbb_dispatcher Event dispatcher object
|
||||
* @param \phpbb\db\driver\driver_interface $db Database object
|
||||
* @param \phpbb\user $user User object
|
||||
* @param string $phpbb_root_path Root path
|
||||
* @param string $php_ext PHP Extension
|
||||
* @param string $forums_table Forums table name
|
||||
* @param string $posts_table Posts table name
|
||||
* @param string $topics_table Topics table name
|
||||
* @param string $users_table Users table name
|
||||
*/
|
||||
public function __construct(\phpbb\auth\auth $auth, \phpbb\config\config $config, \phpbb\event\dispatcher_interface $phpbb_dispatcher, \phpbb\db\driver\driver_interface $db, \phpbb\user $user, $phpbb_root_path, $php_ext, $forums_table, $posts_table, $topics_table, $users_table)
|
||||
{
|
||||
$this->auth = $auth;
|
||||
$this->config = $config;
|
||||
$this->phpbb_dispatcher = $phpbb_dispatcher;
|
||||
$this->db = $db;
|
||||
$this->user = $user;
|
||||
$this->phpbb_root_path = $phpbb_root_path;
|
||||
$this->php_ext = $php_ext;
|
||||
$this->forums_table = $forums_table;
|
||||
$this->posts_table = $posts_table;
|
||||
$this->topics_table = $topics_table;
|
||||
$this->users_table = $users_table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can the current logged-in user soft-delete posts?
|
||||
*
|
||||
* @param $forum_id int Forum ID whose permissions to check
|
||||
* @param $poster_id int Poster ID of the post in question
|
||||
* @param $post_locked bool Is the post locked?
|
||||
* @return bool
|
||||
*/
|
||||
public function can_soft_delete($forum_id, $poster_id, $post_locked)
|
||||
{
|
||||
if ($this->auth->acl_get('m_softdelete', $forum_id))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if ($this->auth->acl_get('f_softdelete', $forum_id) && $poster_id == $this->user->data['user_id'] && !$post_locked)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the topics post count or the forums post/topic count based on permissions
|
||||
*
|
||||
* @param $mode string One of topic_posts, forum_posts or forum_topics
|
||||
* @param $data array Array with the topic/forum data to calculate from
|
||||
* @param $forum_id int The forum id is used for permission checks
|
||||
* @return int Number of posts/topics the user can see in the topic/forum
|
||||
*/
|
||||
public function get_count($mode, $data, $forum_id)
|
||||
{
|
||||
if (!$this->auth->acl_get('m_approve', $forum_id))
|
||||
{
|
||||
return (int) $data[$mode . '_approved'];
|
||||
}
|
||||
|
||||
return (int) $data[$mode . '_approved'] + (int) $data[$mode . '_unapproved'] + (int) $data[$mode . '_softdeleted'];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check topic/post visibility for a given forum ID
|
||||
*
|
||||
* Note: Read permissions are not checked.
|
||||
*
|
||||
* @param $mode string Either "topic" or "post"
|
||||
* @param $forum_id int The forum id is used for permission checks
|
||||
* @param $data array Array with item information to check visibility
|
||||
* @return bool True if the item is visible, false if not
|
||||
*/
|
||||
public function is_visible($mode, $forum_id, $data)
|
||||
{
|
||||
$is_visible = $this->auth->acl_get('m_approve', $forum_id) || $data[$mode . '_visibility'] == ITEM_APPROVED;
|
||||
|
||||
/**
|
||||
* Allow changing the result of calling is_visible
|
||||
*
|
||||
* @event core.phpbb_content_visibility_is_visible
|
||||
* @var bool is_visible Default visibility condition, to be modified by extensions if needed.
|
||||
* @var string mode Either "topic" or "post"
|
||||
* @var int forum_id Forum id of the current item
|
||||
* @var array data Array of item information
|
||||
* @since 3.2.2-RC1
|
||||
*/
|
||||
$vars = array(
|
||||
'is_visible',
|
||||
'mode',
|
||||
'forum_id',
|
||||
'data',
|
||||
);
|
||||
extract($this->phpbb_dispatcher->trigger_event('core.phpbb_content_visibility_is_visible', compact($vars)));
|
||||
|
||||
return $is_visible;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create topic/post visibility SQL for a given forum ID
|
||||
*
|
||||
* Note: Read permissions are not checked.
|
||||
*
|
||||
* @param $mode string Either "topic" or "post"
|
||||
* @param $forum_id int The forum id is used for permission checks
|
||||
* @param $table_alias string Table alias to prefix in SQL queries
|
||||
* @return string The appropriate combination SQL logic for topic/post_visibility
|
||||
*/
|
||||
public function get_visibility_sql($mode, $forum_id, $table_alias = '')
|
||||
{
|
||||
$where_sql = '';
|
||||
|
||||
$get_visibility_sql_overwrite = false;
|
||||
|
||||
/**
|
||||
* Allow changing the result of calling get_visibility_sql
|
||||
*
|
||||
* @event core.phpbb_content_visibility_get_visibility_sql_before
|
||||
* @var string where_sql Extra visibility conditions. It must end with either an SQL "AND" or an "OR"
|
||||
* @var string mode Either "topic" or "post" depending on the query this is being used in
|
||||
* @var array forum_id The forum id in which the search is made.
|
||||
* @var string table_alias Table alias to prefix in SQL queries
|
||||
* @var mixed get_visibility_sql_overwrite If a string, forces the function to return get_forums_visibility_sql_overwrite after executing the event
|
||||
* If false, get_visibility_sql continues normally
|
||||
* It must be either boolean or string
|
||||
* @since 3.1.4-RC1
|
||||
*/
|
||||
$vars = array(
|
||||
'where_sql',
|
||||
'mode',
|
||||
'forum_id',
|
||||
'table_alias',
|
||||
'get_visibility_sql_overwrite',
|
||||
);
|
||||
extract($this->phpbb_dispatcher->trigger_event('core.phpbb_content_visibility_get_visibility_sql_before', compact($vars)));
|
||||
|
||||
if ($get_visibility_sql_overwrite !== false)
|
||||
{
|
||||
return $get_visibility_sql_overwrite;
|
||||
}
|
||||
|
||||
if ($this->auth->acl_get('m_approve', $forum_id))
|
||||
{
|
||||
$where_sql .= '1 = 1';
|
||||
}
|
||||
else
|
||||
{
|
||||
$where_sql .= $table_alias . $mode . '_visibility = ' . ITEM_APPROVED;
|
||||
}
|
||||
|
||||
return '(' . $where_sql . ')';
|
||||
}
|
||||
|
||||
/**
|
||||
* Create topic/post visibility SQL for a set of forums
|
||||
*
|
||||
* Note: Read permissions are not checked. Forums without read permissions
|
||||
* should not be in $forum_ids
|
||||
*
|
||||
* @param $mode string Either "topic" or "post"
|
||||
* @param $forum_ids array Array of forum ids which the posts/topics are limited to
|
||||
* @param $table_alias string Table alias to prefix in SQL queries
|
||||
* @return string The appropriate combination SQL logic for topic/post_visibility
|
||||
*/
|
||||
public function get_forums_visibility_sql($mode, $forum_ids = array(), $table_alias = '')
|
||||
{
|
||||
$where_sql = '';
|
||||
|
||||
$approve_forums = array_keys($this->auth->acl_getf('m_approve', true));
|
||||
if (!empty($forum_ids) && !empty($approve_forums))
|
||||
{
|
||||
$approve_forums = array_intersect($forum_ids, $approve_forums);
|
||||
$forum_ids = array_diff($forum_ids, $approve_forums);
|
||||
}
|
||||
|
||||
$get_forums_visibility_sql_overwrite = false;
|
||||
/**
|
||||
* Allow changing the result of calling get_forums_visibility_sql
|
||||
*
|
||||
* @event core.phpbb_content_visibility_get_forums_visibility_before
|
||||
* @var string where_sql Extra visibility conditions. It must end with either an SQL "AND" or an "OR"
|
||||
* @var string mode Either "topic" or "post" depending on the query this is being used in
|
||||
* @var array forum_ids Array of forum ids which the posts/topics are limited to
|
||||
* @var string table_alias Table alias to prefix in SQL queries
|
||||
* @var array approve_forums Array of forums where the user has m_approve permissions
|
||||
* @var mixed get_forums_visibility_sql_overwrite If a string, forces the function to return get_forums_visibility_sql_overwrite after executing the event
|
||||
* If false, get_forums_visibility_sql continues normally
|
||||
* It must be either boolean or string
|
||||
* @since 3.1.3-RC1
|
||||
*/
|
||||
$vars = array(
|
||||
'where_sql',
|
||||
'mode',
|
||||
'forum_ids',
|
||||
'table_alias',
|
||||
'approve_forums',
|
||||
'get_forums_visibility_sql_overwrite',
|
||||
);
|
||||
extract($this->phpbb_dispatcher->trigger_event('core.phpbb_content_visibility_get_forums_visibility_before', compact($vars)));
|
||||
|
||||
if ($get_forums_visibility_sql_overwrite !== false)
|
||||
{
|
||||
return $get_forums_visibility_sql_overwrite;
|
||||
}
|
||||
|
||||
// Moderator can view all posts/topics in the moderated forums
|
||||
$where_sql .= '(' . $this->db->sql_in_set($table_alias . 'forum_id', $approve_forums, false, true) . ' OR ';
|
||||
// Normal user can view approved items only
|
||||
$where_sql .= '(' . $table_alias . $mode . '_visibility = ' . ITEM_APPROVED . '
|
||||
AND ' . $this->db->sql_in_set($table_alias . 'forum_id', $forum_ids, false, true) . '))';
|
||||
|
||||
return '(' . $where_sql . ')';
|
||||
}
|
||||
|
||||
/**
|
||||
* Create topic/post visibility SQL for all forums on the board
|
||||
*
|
||||
* Note: Read permissions are not checked. Forums without read permissions
|
||||
* should be in $exclude_forum_ids
|
||||
*
|
||||
* @param $mode string Either "topic" or "post"
|
||||
* @param $exclude_forum_ids array Array of forum ids which are excluded
|
||||
* @param $table_alias string Table alias to prefix in SQL queries
|
||||
* @return string The appropriate combination SQL logic for topic/post_visibility
|
||||
*/
|
||||
public function get_global_visibility_sql($mode, $exclude_forum_ids = array(), $table_alias = '')
|
||||
{
|
||||
$where_sqls = array();
|
||||
|
||||
$approve_forums = array_diff(array_keys($this->auth->acl_getf('m_approve', true)), $exclude_forum_ids);
|
||||
|
||||
$visibility_sql_overwrite = null;
|
||||
|
||||
/**
|
||||
* Allow changing the result of calling get_global_visibility_sql
|
||||
*
|
||||
* @event core.phpbb_content_visibility_get_global_visibility_before
|
||||
* @var array where_sqls Array of extra visibility conditions. Will be joined by imploding with "OR".
|
||||
* @var string mode Either "topic" or "post" depending on the query this is being used in
|
||||
* @var array exclude_forum_ids Array of forum ids the current user doesn't have access to
|
||||
* @var string table_alias Table alias to prefix in SQL queries
|
||||
* @var array approve_forums Array of forums where the user has m_approve permissions
|
||||
* @var string visibility_sql_overwrite If not empty, forces the function to return visibility_sql_overwrite after executing the event
|
||||
* @since 3.1.3-RC1
|
||||
*/
|
||||
$vars = array(
|
||||
'where_sqls',
|
||||
'mode',
|
||||
'exclude_forum_ids',
|
||||
'table_alias',
|
||||
'approve_forums',
|
||||
'visibility_sql_overwrite',
|
||||
);
|
||||
extract($this->phpbb_dispatcher->trigger_event('core.phpbb_content_visibility_get_global_visibility_before', compact($vars)));
|
||||
|
||||
if ($visibility_sql_overwrite)
|
||||
{
|
||||
return $visibility_sql_overwrite;
|
||||
}
|
||||
|
||||
// Include approved items in all forums but the excluded
|
||||
$where_sqls[] = '(' . $this->db->sql_in_set($table_alias . 'forum_id', $exclude_forum_ids, true, true) . '
|
||||
AND ' . $table_alias . $mode . '_visibility = ' . ITEM_APPROVED . ')';
|
||||
|
||||
// If user has moderator permissions, add everything in the moderated forums
|
||||
if (count($approve_forums))
|
||||
{
|
||||
$where_sqls[] = $this->db->sql_in_set($table_alias . 'forum_id', $approve_forums);
|
||||
}
|
||||
|
||||
return '(' . implode(' OR ', $where_sqls) . ')';
|
||||
}
|
||||
|
||||
/**
|
||||
* Change visibility status of one post or all posts of a topic
|
||||
*
|
||||
* @param $visibility int Element of {ITEM_APPROVED, ITEM_DELETED, ITEM_REAPPROVE}
|
||||
* @param $post_id mixed Post ID or array of post IDs to act on,
|
||||
* if it is empty, all posts of topic_id will be modified
|
||||
* @param $topic_id int Topic where $post_id is found
|
||||
* @param $forum_id int Forum where $topic_id is found
|
||||
* @param $user_id int User performing the action
|
||||
* @param $time int Timestamp when the action is performed
|
||||
* @param $reason string Reason why the visibility was changed.
|
||||
* @param $is_starter bool Is this the first post of the topic changed?
|
||||
* @param $is_latest bool Is this the last post of the topic changed?
|
||||
* @param $limit_visibility mixed Limit updating per topic_id to a certain visibility
|
||||
* @param $limit_delete_time mixed Limit updating per topic_id to a certain deletion time
|
||||
* @return array Changed post data, empty array if an error occurred.
|
||||
*/
|
||||
public function set_post_visibility($visibility, $post_id, $topic_id, $forum_id, $user_id, $time, $reason, $is_starter, $is_latest, $limit_visibility = false, $limit_delete_time = false)
|
||||
{
|
||||
if (!in_array($visibility, array(ITEM_APPROVED, ITEM_DELETED, ITEM_REAPPROVE)))
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
if ($post_id)
|
||||
{
|
||||
if (is_array($post_id))
|
||||
{
|
||||
$where_sql = $this->db->sql_in_set('post_id', array_map('intval', $post_id));
|
||||
}
|
||||
else
|
||||
{
|
||||
$where_sql = 'post_id = ' . (int) $post_id;
|
||||
}
|
||||
$where_sql .= ' AND topic_id = ' . (int) $topic_id;
|
||||
}
|
||||
else
|
||||
{
|
||||
$where_sql = 'topic_id = ' . (int) $topic_id;
|
||||
|
||||
// Limit the posts to a certain visibility and deletion time
|
||||
// This allows us to only restore posts, that were approved
|
||||
// when the topic got soft deleted. So previous soft deleted
|
||||
// and unapproved posts are still soft deleted/unapproved
|
||||
if ($limit_visibility !== false)
|
||||
{
|
||||
$where_sql .= ' AND post_visibility = ' . (int) $limit_visibility;
|
||||
}
|
||||
|
||||
if ($limit_delete_time !== false)
|
||||
{
|
||||
$where_sql .= ' AND post_delete_time = ' . (int) $limit_delete_time;
|
||||
}
|
||||
}
|
||||
|
||||
$sql = 'SELECT poster_id, post_id, post_postcount, post_visibility
|
||||
FROM ' . $this->posts_table . '
|
||||
WHERE ' . $where_sql;
|
||||
$result = $this->db->sql_query($sql);
|
||||
|
||||
$post_ids = $poster_postcounts = $postcounts = $postcount_visibility = array();
|
||||
while ($row = $this->db->sql_fetchrow($result))
|
||||
{
|
||||
$post_ids[] = (int) $row['post_id'];
|
||||
|
||||
if ($row['post_visibility'] != $visibility)
|
||||
{
|
||||
if ($row['post_postcount'] && !isset($poster_postcounts[(int) $row['poster_id']]))
|
||||
{
|
||||
$poster_postcounts[(int) $row['poster_id']] = 1;
|
||||
}
|
||||
else if ($row['post_postcount'])
|
||||
{
|
||||
$poster_postcounts[(int) $row['poster_id']]++;
|
||||
}
|
||||
|
||||
if (!isset($postcount_visibility[$row['post_visibility']]))
|
||||
{
|
||||
$postcount_visibility[$row['post_visibility']] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
$postcount_visibility[$row['post_visibility']]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
if (empty($post_ids))
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
if (!function_exists('truncate_string'))
|
||||
{
|
||||
include($this->phpbb_root_path . 'includes/functions_content.' . $this->php_ext);
|
||||
}
|
||||
|
||||
$data = array(
|
||||
'post_visibility' => (int) $visibility,
|
||||
'post_delete_user' => (int) $user_id,
|
||||
'post_delete_time' => ((int) $time) ?: time(),
|
||||
'post_delete_reason' => truncate_string($reason, 255, 255, false),
|
||||
);
|
||||
/**
|
||||
* Perform actions right before the query to change post visibility
|
||||
*
|
||||
* @event core.set_post_visibility_before_sql
|
||||
* @var int visibility Element of {ITEM_APPROVED, ITEM_DELETED, ITEM_REAPPROVE}
|
||||
* @var array post_id Array containing all post IDs to be modified. If blank, all posts within the topic are modified.
|
||||
* @var int topic_id Topic of the post IDs to be modified.
|
||||
* @var int forum_id Forum ID that the topic_id resides in.
|
||||
* @var int user_id User ID doing this action.
|
||||
* @var int time Timestamp of this action.
|
||||
* @var string reason Reason specified by the user for this change.
|
||||
* @var bool is_starter Are we changing the topic's starter?
|
||||
* @var bool is_latest Are we changing the topic's latest post?
|
||||
* @var array data The data array for this action.
|
||||
* @since 3.1.10-RC1
|
||||
* @changed 3.2.2-RC1 Use time instead of non-existent timestamp
|
||||
*/
|
||||
$vars = array(
|
||||
'visibility',
|
||||
'post_id',
|
||||
'topic_id',
|
||||
'forum_id',
|
||||
'user_id',
|
||||
'time',
|
||||
'reason',
|
||||
'is_starter',
|
||||
'is_latest',
|
||||
'data',
|
||||
);
|
||||
extract($this->phpbb_dispatcher->trigger_event('core.set_post_visibility_before_sql', compact($vars)));
|
||||
$sql = 'UPDATE ' . $this->posts_table . '
|
||||
SET ' . $this->db->sql_build_array('UPDATE', $data) . '
|
||||
WHERE ' . $this->db->sql_in_set('post_id', $post_ids);
|
||||
$this->db->sql_query($sql);
|
||||
|
||||
// Group the authors by post count, to reduce the number of queries
|
||||
foreach ($poster_postcounts as $poster_id => $num_posts)
|
||||
{
|
||||
$postcounts[$num_posts][] = $poster_id;
|
||||
}
|
||||
|
||||
// Update users postcounts
|
||||
foreach ($postcounts as $num_posts => $poster_ids)
|
||||
{
|
||||
if (in_array($visibility, array(ITEM_REAPPROVE, ITEM_DELETED)))
|
||||
{
|
||||
$sql = 'UPDATE ' . $this->users_table . '
|
||||
SET user_posts = 0
|
||||
WHERE ' . $this->db->sql_in_set('user_id', $poster_ids) . '
|
||||
AND user_posts < ' . $num_posts;
|
||||
$this->db->sql_query($sql);
|
||||
|
||||
$sql = 'UPDATE ' . $this->users_table . '
|
||||
SET user_posts = user_posts - ' . $num_posts . '
|
||||
WHERE ' . $this->db->sql_in_set('user_id', $poster_ids) . '
|
||||
AND user_posts >= ' . $num_posts;
|
||||
$this->db->sql_query($sql);
|
||||
}
|
||||
else
|
||||
{
|
||||
$sql = 'UPDATE ' . $this->users_table . '
|
||||
SET user_posts = user_posts + ' . $num_posts . '
|
||||
WHERE ' . $this->db->sql_in_set('user_id', $poster_ids);
|
||||
$this->db->sql_query($sql);
|
||||
}
|
||||
}
|
||||
|
||||
$update_topic_postcount = true;
|
||||
|
||||
// Sync the first/last topic information if needed
|
||||
if (!$is_starter && $is_latest)
|
||||
{
|
||||
if (!function_exists('update_post_information'))
|
||||
{
|
||||
include($this->phpbb_root_path . 'includes/functions_posting.' . $this->php_ext);
|
||||
}
|
||||
|
||||
// update_post_information can only update the last post info ...
|
||||
if ($topic_id)
|
||||
{
|
||||
update_post_information('topic', $topic_id, false);
|
||||
}
|
||||
if ($forum_id)
|
||||
{
|
||||
update_post_information('forum', $forum_id, false);
|
||||
}
|
||||
}
|
||||
else if ($is_starter && $topic_id)
|
||||
{
|
||||
if (!function_exists('sync'))
|
||||
{
|
||||
include($this->phpbb_root_path . 'includes/functions_admin.' . $this->php_ext);
|
||||
}
|
||||
|
||||
// ... so we need to use sync, if the first post is changed.
|
||||
// The forum is resynced recursive by sync() itself.
|
||||
sync('topic', 'topic_id', $topic_id, true);
|
||||
|
||||
// sync recalculates the topic replies and forum posts by itself, so we don't do that.
|
||||
$update_topic_postcount = false;
|
||||
}
|
||||
|
||||
$topic_update_array = array();
|
||||
// Update the topic's reply count and the forum's post count
|
||||
if ($update_topic_postcount)
|
||||
{
|
||||
$field_alias = array(
|
||||
ITEM_APPROVED => 'posts_approved',
|
||||
ITEM_UNAPPROVED => 'posts_unapproved',
|
||||
ITEM_DELETED => 'posts_softdeleted',
|
||||
ITEM_REAPPROVE => 'posts_unapproved',
|
||||
);
|
||||
$cur_posts = array_fill_keys($field_alias, 0);
|
||||
|
||||
foreach ($postcount_visibility as $post_visibility => $visibility_posts)
|
||||
{
|
||||
$cur_posts[$field_alias[(int) $post_visibility]] += $visibility_posts;
|
||||
}
|
||||
|
||||
$sql_ary = array();
|
||||
$recipient_field = $field_alias[$visibility];
|
||||
|
||||
foreach ($cur_posts as $field => $count)
|
||||
{
|
||||
// Decrease the count for the old statuses.
|
||||
if ($count && $field != $recipient_field)
|
||||
{
|
||||
$sql_ary[$field] = " - $count";
|
||||
}
|
||||
}
|
||||
// Add up the count from all statuses excluding the recipient status.
|
||||
$count_increase = array_sum(array_diff($cur_posts, array($recipient_field)));
|
||||
|
||||
if ($count_increase)
|
||||
{
|
||||
$sql_ary[$recipient_field] = " + $count_increase";
|
||||
}
|
||||
|
||||
if (count($sql_ary))
|
||||
{
|
||||
$forum_sql = array();
|
||||
|
||||
foreach ($sql_ary as $field => $value_change)
|
||||
{
|
||||
$topic_update_array[] = 'topic_' . $field . ' = topic_' . $field . $value_change;
|
||||
$forum_sql[] = 'forum_' . $field . ' = forum_' . $field . $value_change;
|
||||
}
|
||||
|
||||
$sql = 'UPDATE ' . $this->forums_table . '
|
||||
SET ' . implode(', ', $forum_sql) . '
|
||||
WHERE forum_id = ' . (int) $forum_id;
|
||||
$this->db->sql_query($sql);
|
||||
}
|
||||
}
|
||||
|
||||
if ($post_id)
|
||||
{
|
||||
$sql = 'SELECT 1 AS has_attachments
|
||||
FROM ' . POSTS_TABLE . '
|
||||
WHERE topic_id = ' . (int) $topic_id . '
|
||||
AND post_attachment = 1
|
||||
AND post_visibility = ' . ITEM_APPROVED . '
|
||||
AND ' . $this->db->sql_in_set('post_id', $post_id, true);
|
||||
$result = $this->db->sql_query_limit($sql, 1);
|
||||
|
||||
$has_attachment = (bool) $this->db->sql_fetchfield('has_attachments');
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
if ($has_attachment && $visibility == ITEM_APPROVED)
|
||||
{
|
||||
$topic_update_array[] = 'topic_attachment = 1';
|
||||
}
|
||||
else if (!$has_attachment && $visibility != ITEM_APPROVED)
|
||||
{
|
||||
$topic_update_array[] = 'topic_attachment = 0';
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($topic_update_array))
|
||||
{
|
||||
// Update the number for replies and posts, and update the attachments flag
|
||||
$sql = 'UPDATE ' . $this->topics_table . '
|
||||
SET ' . implode(', ', $topic_update_array) . '
|
||||
WHERE topic_id = ' . (int) $topic_id;
|
||||
$this->db->sql_query($sql);
|
||||
}
|
||||
/**
|
||||
* Perform actions after all steps to changing post visibility
|
||||
*
|
||||
* @event core.set_post_visibility_after
|
||||
* @var int visibility Element of {ITEM_APPROVED, ITEM_DELETED, ITEM_REAPPROVE}
|
||||
* @var array post_id Array containing all post IDs to be modified. If blank, all posts within the topic are modified.
|
||||
* @var int topic_id Topic of the post IDs to be modified.
|
||||
* @var int forum_id Forum ID that the topic_id resides in.
|
||||
* @var int user_id User ID doing this action.
|
||||
* @var int time Timestamp of this action.
|
||||
* @var string reason Reason specified by the user for this change.
|
||||
* @var bool is_starter Are we changing the topic's starter?
|
||||
* @var bool is_latest Are we changing the topic's latest post?
|
||||
* @var array data The data array for this action.
|
||||
* @since 3.1.10-RC1
|
||||
* @changed 3.2.2-RC1 Use time instead of non-existent timestamp
|
||||
*/
|
||||
$vars = array(
|
||||
'visibility',
|
||||
'post_id',
|
||||
'topic_id',
|
||||
'forum_id',
|
||||
'user_id',
|
||||
'time',
|
||||
'reason',
|
||||
'is_starter',
|
||||
'is_latest',
|
||||
'data',
|
||||
);
|
||||
extract($this->phpbb_dispatcher->trigger_event('core.set_post_visibility_after', compact($vars)));
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set topic visibility
|
||||
*
|
||||
* Allows approving (which is akin to undeleting/restore) or soft deleting an entire topic.
|
||||
* Calls set_post_visibility as needed.
|
||||
*
|
||||
* Note: By default, when a soft deleted topic is restored. Only posts that
|
||||
* were approved at the time of soft deleting, are being restored.
|
||||
* Same applies to soft deleting. Only approved posts will be marked
|
||||
* as soft deleted.
|
||||
* If you want to update all posts, use the force option.
|
||||
*
|
||||
* @param $visibility int Element of {ITEM_APPROVED, ITEM_DELETED, ITEM_REAPPROVE}
|
||||
* @param $topic_id mixed Topic ID to act on
|
||||
* @param $forum_id int Forum where $topic_id is found
|
||||
* @param $user_id int User performing the action
|
||||
* @param $time int Timestamp when the action is performed
|
||||
* @param $reason string Reason why the visibilty was changed.
|
||||
* @param $force_update_all bool Force to update all posts within the topic
|
||||
* @return array Changed topic data, empty array if an error occured.
|
||||
*/
|
||||
public function set_topic_visibility($visibility, $topic_id, $forum_id, $user_id, $time, $reason, $force_update_all = false)
|
||||
{
|
||||
if (!in_array($visibility, array(ITEM_APPROVED, ITEM_DELETED, ITEM_REAPPROVE)))
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
if (!$force_update_all)
|
||||
{
|
||||
$sql = 'SELECT topic_visibility, topic_delete_time
|
||||
FROM ' . $this->topics_table . '
|
||||
WHERE topic_id = ' . (int) $topic_id;
|
||||
$result = $this->db->sql_query($sql);
|
||||
$original_topic_data = $this->db->sql_fetchrow($result);
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
if (!$original_topic_data)
|
||||
{
|
||||
// The topic does not exist...
|
||||
return array();
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('truncate_string'))
|
||||
{
|
||||
include($this->phpbb_root_path . 'includes/functions_content.' . $this->php_ext);
|
||||
}
|
||||
|
||||
// Note, we do not set a reason for the posts, just for the topic
|
||||
$data = array(
|
||||
'topic_visibility' => (int) $visibility,
|
||||
'topic_delete_user' => (int) $user_id,
|
||||
'topic_delete_time' => ((int) $time) ?: time(),
|
||||
'topic_delete_reason' => truncate_string($reason, 255, 255, false),
|
||||
);
|
||||
/**
|
||||
* Perform actions right before the query to change topic visibility
|
||||
*
|
||||
* @event core.set_topic_visibility_before_sql
|
||||
* @var int visibility Element of {ITEM_APPROVED, ITEM_DELETED, ITEM_REAPPROVE}
|
||||
* @var int topic_id Topic of the post IDs to be modified.
|
||||
* @var int forum_id Forum ID that the topic_id resides in.
|
||||
* @var int user_id User ID doing this action.
|
||||
* @var int time Timestamp of this action.
|
||||
* @var string reason Reason specified by the user for this change.
|
||||
* @var bool force_update_all Force an update on all posts within the topic, regardless of their current approval state.
|
||||
* @var array data The data array for this action.
|
||||
* @since 3.1.10-RC1
|
||||
* @changed 3.2.2-RC1 Use time instead of non-existent timestamp
|
||||
*/
|
||||
$vars = array(
|
||||
'visibility',
|
||||
'topic_id',
|
||||
'forum_id',
|
||||
'user_id',
|
||||
'time',
|
||||
'reason',
|
||||
'force_update_all',
|
||||
'data',
|
||||
);
|
||||
extract($this->phpbb_dispatcher->trigger_event('core.set_topic_visibility_before_sql', compact($vars)));
|
||||
$sql = 'UPDATE ' . $this->topics_table . '
|
||||
SET ' . $this->db->sql_build_array('UPDATE', $data) . '
|
||||
WHERE topic_id = ' . (int) $topic_id;
|
||||
$this->db->sql_query($sql);
|
||||
|
||||
if (!$this->db->sql_affectedrows())
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
if (!$force_update_all && $original_topic_data['topic_delete_time'] && $original_topic_data['topic_visibility'] == ITEM_DELETED && $visibility == ITEM_APPROVED)
|
||||
{
|
||||
// If we're restoring a topic we only restore posts, that were soft deleted through the topic soft deletion.
|
||||
$this->set_post_visibility($visibility, false, $topic_id, $forum_id, $user_id, $time, '', true, true, $original_topic_data['topic_visibility'], $original_topic_data['topic_delete_time']);
|
||||
}
|
||||
else if (!$force_update_all && $original_topic_data['topic_visibility'] == ITEM_APPROVED && $visibility == ITEM_DELETED)
|
||||
{
|
||||
// If we're soft deleting a topic we only mark approved posts as soft deleted.
|
||||
$this->set_post_visibility($visibility, false, $topic_id, $forum_id, $user_id, $time, '', true, true, $original_topic_data['topic_visibility']);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->set_post_visibility($visibility, false, $topic_id, $forum_id, $user_id, $time, '', true, true);
|
||||
}
|
||||
/**
|
||||
* Perform actions after all steps to changing topic visibility
|
||||
*
|
||||
* @event core.set_topic_visibility_after
|
||||
* @var int visibility Element of {ITEM_APPROVED, ITEM_DELETED, ITEM_REAPPROVE}
|
||||
* @var int topic_id Topic of the post IDs to be modified.
|
||||
* @var int forum_id Forum ID that the topic_id resides in.
|
||||
* @var int user_id User ID doing this action.
|
||||
* @var int time Timestamp of this action.
|
||||
* @var string reason Reason specified by the user for this change.
|
||||
* @var bool force_update_all Force an update on all posts within the topic, regardless of their current approval state.
|
||||
* @var array data The data array for this action.
|
||||
* @since 3.1.10-RC1
|
||||
* @changed 3.2.2-RC1 Use time instead of non-existent timestamp
|
||||
*/
|
||||
$vars = array(
|
||||
'visibility',
|
||||
'topic_id',
|
||||
'forum_id',
|
||||
'user_id',
|
||||
'time',
|
||||
'reason',
|
||||
'force_update_all',
|
||||
'data',
|
||||
);
|
||||
extract($this->phpbb_dispatcher->trigger_event('core.set_topic_visibility_after', compact($vars)));
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add post to topic and forum statistics
|
||||
*
|
||||
* @param $data array Contains information from the topics table about given topic
|
||||
* @param &$sql_data array Populated with the SQL changes, may be empty at call time
|
||||
* @return null
|
||||
*/
|
||||
public function add_post_to_statistic($data, &$sql_data)
|
||||
{
|
||||
$sql_data[$this->topics_table] = (($sql_data[$this->topics_table]) ? $sql_data[$this->topics_table] . ', ' : '') . 'topic_posts_approved = topic_posts_approved + 1';
|
||||
|
||||
$sql_data[$this->forums_table] = (($sql_data[$this->forums_table]) ? $sql_data[$this->forums_table] . ', ' : '') . 'forum_posts_approved = forum_posts_approved + 1';
|
||||
|
||||
if ($data['post_postcount'])
|
||||
{
|
||||
$sql_data[$this->users_table] = (($sql_data[$this->users_table]) ? $sql_data[$this->users_table] . ', ' : '') . 'user_posts = user_posts + 1';
|
||||
}
|
||||
|
||||
$this->config->increment('num_posts', 1, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove post from topic and forum statistics
|
||||
*
|
||||
* @param $data array Contains information from the topics table about given topic
|
||||
* @param &$sql_data array Populated with the SQL changes, may be empty at call time
|
||||
* @return null
|
||||
*/
|
||||
public function remove_post_from_statistic($data, &$sql_data)
|
||||
{
|
||||
if ($data['post_visibility'] == ITEM_APPROVED)
|
||||
{
|
||||
$sql_data[$this->topics_table] = ((!empty($sql_data[$this->topics_table])) ? $sql_data[$this->topics_table] . ', ' : '') . 'topic_posts_approved = topic_posts_approved - 1';
|
||||
$sql_data[$this->forums_table] = ((!empty($sql_data[$this->forums_table])) ? $sql_data[$this->forums_table] . ', ' : '') . 'forum_posts_approved = forum_posts_approved - 1';
|
||||
|
||||
if ($data['post_postcount'])
|
||||
{
|
||||
$sql_data[$this->users_table] = ((!empty($sql_data[$this->users_table])) ? $sql_data[$this->users_table] . ', ' : '') . 'user_posts = user_posts - 1';
|
||||
}
|
||||
|
||||
$this->config->increment('num_posts', -1, false);
|
||||
}
|
||||
else if ($data['post_visibility'] == ITEM_UNAPPROVED || $data['post_visibility'] == ITEM_REAPPROVE)
|
||||
{
|
||||
$sql_data[FORUMS_TABLE] = (($sql_data[FORUMS_TABLE]) ? $sql_data[FORUMS_TABLE] . ', ' : '') . 'forum_posts_unapproved = forum_posts_unapproved - 1';
|
||||
$sql_data[TOPICS_TABLE] = (($sql_data[TOPICS_TABLE]) ? $sql_data[TOPICS_TABLE] . ', ' : '') . 'topic_posts_unapproved = topic_posts_unapproved - 1';
|
||||
}
|
||||
else if ($data['post_visibility'] == ITEM_DELETED)
|
||||
{
|
||||
$sql_data[FORUMS_TABLE] = (($sql_data[FORUMS_TABLE]) ? $sql_data[FORUMS_TABLE] . ', ' : '') . 'forum_posts_softdeleted = forum_posts_softdeleted - 1';
|
||||
$sql_data[TOPICS_TABLE] = (($sql_data[TOPICS_TABLE]) ? $sql_data[TOPICS_TABLE] . ', ' : '') . 'topic_posts_softdeleted = topic_posts_softdeleted - 1';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove topic from forum statistics
|
||||
*
|
||||
* @param $data array Post and topic data
|
||||
* @param &$sql_data array Populated with the SQL changes, may be empty at call time
|
||||
* @return null
|
||||
*/
|
||||
public function remove_topic_from_statistic($data, &$sql_data)
|
||||
{
|
||||
if ($data['topic_visibility'] == ITEM_APPROVED)
|
||||
{
|
||||
$sql_data[FORUMS_TABLE] .= 'forum_posts_approved = forum_posts_approved - 1, forum_topics_approved = forum_topics_approved - 1';
|
||||
|
||||
if ($data['post_postcount'])
|
||||
{
|
||||
$sql_data[$this->users_table] = ((!empty($sql_data[$this->users_table])) ? $sql_data[$this->users_table] . ', ' : '') . 'user_posts = user_posts - 1';
|
||||
}
|
||||
}
|
||||
else if ($data['topic_visibility'] == ITEM_UNAPPROVED || $data['post_visibility'] == ITEM_REAPPROVE)
|
||||
{
|
||||
$sql_data[FORUMS_TABLE] .= 'forum_posts_unapproved = forum_posts_unapproved - 1, forum_topics_unapproved = forum_topics_unapproved - 1';
|
||||
}
|
||||
else if ($data['topic_visibility'] == ITEM_DELETED)
|
||||
{
|
||||
$sql_data[FORUMS_TABLE] .= 'forum_posts_softdeleted = forum_posts_softdeleted - 1, forum_topics_softdeleted = forum_topics_softdeleted - 1';
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
21
phpbb/controller/exception.php
Normal file
21
phpbb/controller/exception.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\controller;
|
||||
|
||||
/**
|
||||
* Controller exception class
|
||||
*/
|
||||
class exception extends \phpbb\exception\runtime_exception
|
||||
{
|
||||
}
|
||||
195
phpbb/controller/helper.php
Normal file
195
phpbb/controller/helper.php
Normal file
@@ -0,0 +1,195 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\controller;
|
||||
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||
|
||||
/**
|
||||
* Controller helper class, contains methods that do things for controllers
|
||||
*/
|
||||
class helper
|
||||
{
|
||||
/**
|
||||
* Template object
|
||||
* @var \phpbb\template\template
|
||||
*/
|
||||
protected $template;
|
||||
|
||||
/**
|
||||
* User object
|
||||
* @var \phpbb\user
|
||||
*/
|
||||
protected $user;
|
||||
|
||||
/**
|
||||
* config object
|
||||
* @var \phpbb\config\config
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/* @var \phpbb\symfony_request */
|
||||
protected $symfony_request;
|
||||
|
||||
/* @var \phpbb\request\request_interface */
|
||||
protected $request;
|
||||
|
||||
/**
|
||||
* @var \phpbb\routing\helper
|
||||
*/
|
||||
protected $routing_helper;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \phpbb\template\template $template Template object
|
||||
* @param \phpbb\user $user User object
|
||||
* @param \phpbb\config\config $config Config object
|
||||
* @param \phpbb\symfony_request $symfony_request Symfony Request object
|
||||
* @param \phpbb\request\request_interface $request phpBB request object
|
||||
* @param \phpbb\routing\helper $routing_helper Helper to generate the routes
|
||||
*/
|
||||
public function __construct(\phpbb\template\template $template, \phpbb\user $user, \phpbb\config\config $config, \phpbb\symfony_request $symfony_request, \phpbb\request\request_interface $request, \phpbb\routing\helper $routing_helper)
|
||||
{
|
||||
$this->template = $template;
|
||||
$this->user = $user;
|
||||
$this->config = $config;
|
||||
$this->symfony_request = $symfony_request;
|
||||
$this->request = $request;
|
||||
$this->routing_helper = $routing_helper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Automate setting up the page and creating the response object.
|
||||
*
|
||||
* @param string $template_file The template handle to render
|
||||
* @param string $page_title The title of the page to output
|
||||
* @param int $status_code The status code to be sent to the page header
|
||||
* @param bool $display_online_list Do we display online users list
|
||||
* @param int $item_id Restrict online users to item id
|
||||
* @param string $item Restrict online users to a certain session item, e.g. forum for session_forum_id
|
||||
* @param bool $send_headers Whether headers should be sent by page_header(). Defaults to false for controllers.
|
||||
*
|
||||
* @return Response object containing rendered page
|
||||
*/
|
||||
public function render($template_file, $page_title = '', $status_code = 200, $display_online_list = false, $item_id = 0, $item = 'forum', $send_headers = false)
|
||||
{
|
||||
page_header($page_title, $display_online_list, $item_id, $item, $send_headers);
|
||||
|
||||
$this->template->set_filenames(array(
|
||||
'body' => $template_file,
|
||||
));
|
||||
|
||||
page_footer(true, false, false);
|
||||
|
||||
$headers = !empty($this->user->data['is_bot']) ? array('X-PHPBB-IS-BOT' => 'yes') : array();
|
||||
|
||||
return new Response($this->template->assign_display('body'), $status_code, $headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a URL to a route
|
||||
*
|
||||
* @param string $route Name of the route to travel
|
||||
* @param array $params String or array of additional url parameters
|
||||
* @param bool $is_amp Is url using & (true) or & (false)
|
||||
* @param string|bool $session_id Possibility to use a custom session id instead of the global one
|
||||
* @param bool|string $reference_type The type of reference to be generated (one of the constants)
|
||||
* @return string The URL already passed through append_sid()
|
||||
*/
|
||||
public function route($route, array $params = array(), $is_amp = true, $session_id = false, $reference_type = UrlGeneratorInterface::ABSOLUTE_PATH)
|
||||
{
|
||||
return $this->routing_helper->route($route, $params, $is_amp, $session_id, $reference_type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Output an error, effectively the same thing as trigger_error
|
||||
*
|
||||
* @param string $message The error message
|
||||
* @param int $code The error code (e.g. 404, 500, 503, etc.)
|
||||
* @return Response A Response instance
|
||||
*
|
||||
* @deprecated 3.1.3 (To be removed: 3.3.0) Use exceptions instead.
|
||||
*/
|
||||
public function error($message, $code = 500)
|
||||
{
|
||||
return $this->message($message, array(), 'INFORMATION', $code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Output a message
|
||||
*
|
||||
* In case of an error, please throw an exception instead
|
||||
*
|
||||
* @param string $message The message to display (must be a language variable)
|
||||
* @param array $parameters The parameters to use with the language var
|
||||
* @param string $title Title for the message (must be a language variable)
|
||||
* @param int $code The HTTP status code (e.g. 404, 500, 503, etc.)
|
||||
* @return Response A Response instance
|
||||
*/
|
||||
public function message($message, array $parameters = array(), $title = 'INFORMATION', $code = 200)
|
||||
{
|
||||
array_unshift($parameters, $message);
|
||||
$message_text = call_user_func_array(array($this->user, 'lang'), $parameters);
|
||||
$message_title = $this->user->lang($title);
|
||||
|
||||
if ($this->request->is_ajax())
|
||||
{
|
||||
global $refresh_data;
|
||||
|
||||
return new JsonResponse(
|
||||
array(
|
||||
'MESSAGE_TITLE' => $message_title,
|
||||
'MESSAGE_TEXT' => $message_text,
|
||||
'S_USER_WARNING' => false,
|
||||
'S_USER_NOTICE' => false,
|
||||
'REFRESH_DATA' => (!empty($refresh_data)) ? $refresh_data : null
|
||||
),
|
||||
$code
|
||||
);
|
||||
}
|
||||
|
||||
$this->template->assign_vars(array(
|
||||
'MESSAGE_TEXT' => $message_text,
|
||||
'MESSAGE_TITLE' => $message_title,
|
||||
));
|
||||
|
||||
return $this->render('message_body.html', $message_title, $code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns automatic refresh time meta tag in template
|
||||
*
|
||||
* @param int $time time in seconds, when redirection should occur
|
||||
* @param string $url the URL where the user should be redirected
|
||||
* @return null
|
||||
*/
|
||||
public function assign_meta_refresh_var($time, $url)
|
||||
{
|
||||
$this->template->assign_vars(array(
|
||||
'META' => '<meta http-equiv="refresh" content="' . $time . '; url=' . $url . '" />',
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current url
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_current_url()
|
||||
{
|
||||
return generate_board_url(true) . $this->request->escape($this->symfony_request->getRequestUri(), true);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user