Merge branch 'develop'
This commit is contained in:
		
						commit
						1bf3fba756
					
				
							
								
								
									
										149
									
								
								README.markdown
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										149
									
								
								README.markdown
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,149 @@ | ||||
| ``` | ||||
|      _________.__     .__                   .__         ________    | ||||
|     /   _____/|  |__  |__|  _____    _____  |__|  ____  \_____  \   | ||||
|     \_____  \ |  |  \ |  | /     \  /     \ |  |_/ __ \  /  ____/   | ||||
|     /        \|   Y  \|  ||  Y Y  \|  Y Y  \|  |\  ___/ /       \   | ||||
|    /_______  /|___|  /|__||__|_|  /|__|_|  /|__| \___  >\_______ \  | ||||
|            \/      \/           \/       \/          \/         \/  | ||||
|                                                                  | ||||
| ``` | ||||
| 
 | ||||
| # Shimmie | ||||
| 
 | ||||
| [](https://travis-ci.org/shish/shimmie2) | ||||
| 
 | ||||
| This is the main branch of Shimmie, if you know anything at all about running | ||||
| websites, this is the version to use. | ||||
| 
 | ||||
| Alternatively if you want a version that will never have significant changes, | ||||
| check out one of the versioned branches. | ||||
| 
 | ||||
| # Requirements | ||||
| 
 | ||||
| - MySQL/MariaDB 5.1+ (with experimental support for PostgreSQL 8+ and SQLite 3) | ||||
| - PHP 5.3.7+ | ||||
| - GD or ImageMagick | ||||
| 
 | ||||
| # Installation | ||||
| 
 | ||||
| 1. Create a blank database | ||||
| 2. Unzip shimmie into a folder on the web host | ||||
| 3. Visit the folder with a web browser | ||||
| 4. Enter the location of the database | ||||
| 5. Click "install". Hopefully you'll end up at the welcome screen; if | ||||
|    not, you should be given instructions on how to fix any errors~ | ||||
| 
 | ||||
| ## Upgrade from 2.3.X | ||||
| 
 | ||||
| 1. Backup your current files and database! | ||||
| 2. Unzip into a clean folder | ||||
| 3. Copy across the images, thumbs, and data folders | ||||
| 4. Move `old/config.php` to `new/data/config/shimmie.conf.php` | ||||
| 5. Edit `shimmie.conf.php` to use the new database connection format: | ||||
| 
 | ||||
| OLD Format: | ||||
| ```php | ||||
| $database_dsn = "<proto>://<username>:<password>@<host>/<database>"; | ||||
| ``` | ||||
| 
 | ||||
| NEW Format: | ||||
| ```php | ||||
| define("DATABASE_DSN", "<proto>:user=<username>;password=<password>;host=<host>;dbname=<database>"); | ||||
| ``` | ||||
| 
 | ||||
| The rest should be automatic~ | ||||
| 
 | ||||
| If there are any errors with the upgrade process, `in_upgrade=true` will | ||||
| be left in the config table and the process will be paused for the admin | ||||
| to investigate. | ||||
| 
 | ||||
| Deleting this config entry and refreshing the page should continue the upgrade from where it left off. | ||||
| 
 | ||||
| 
 | ||||
| ### Upgrade from earlier versions | ||||
| 
 | ||||
| I very much recommend going via each major release in turn (eg, 2.0.6 | ||||
| -> 2.1.3 -> 2.2.4 -> 2.3.0 rather than 2.0.6 -> 2.3.0). | ||||
| 
 | ||||
| While the basic database and file formats haven't changed *completely*, it's different | ||||
| enough to be a pain. | ||||
| 
 | ||||
| 
 | ||||
| ## Custom Configuration | ||||
| 
 | ||||
| Various aspects of Shimmie can be configured to suit your site specific needs | ||||
| via the file `data/config/shimmie.conf.php` (created after installation). | ||||
| 
 | ||||
| Take a look at `core/sys_config.inc.php` for the available options that can | ||||
| be used. | ||||
| 
 | ||||
| 
 | ||||
| #### Custom User Classes | ||||
| 
 | ||||
| User classes can be added to or altered by placing them in | ||||
| `data/config/user-classes.conf.php`. | ||||
| 
 | ||||
| For example, one can override the default anonymous "allow nothing" permissions like so: | ||||
| 
 | ||||
| ```php | ||||
| new UserClass("anonymous", "base", array( | ||||
| 	"create_comment" => True, | ||||
| 	"edit_image_tag" => True, | ||||
| 	"edit_image_source" => True, | ||||
| 	"create_image_report" => True, | ||||
| )); | ||||
| ``` | ||||
| 
 | ||||
| For a moderator class, being a regular user who can delete images and comments: | ||||
| 
 | ||||
| ```php | ||||
| new UserClass("moderator", "user", array( | ||||
| 	"delete_image" => True, | ||||
| 	"delete_comment" => True, | ||||
| )); | ||||
| ``` | ||||
| 
 | ||||
| For a list of permissions, see `core/userclass.class.php` | ||||
| 
 | ||||
| 
 | ||||
| # Development Info | ||||
| 
 | ||||
| ui-* cookies are for the client-side scripts only; in some configurations | ||||
| (eg with varnish cache) they will be stripped before they reach the server | ||||
| 
 | ||||
| shm-* CSS classes are for javascript to hook into; if you're customising | ||||
| themes, be careful with these, and avoid styling them, eg: | ||||
| 
 | ||||
| - shm-thumb = outermost element of a thumbnail | ||||
|    * data-tags | ||||
|    * data-post-id | ||||
| - shm-toggler = click this to toggle elements that match the selector | ||||
|   * data-toggle-sel | ||||
| - shm-unlocker = click this to unlock elements that match the selector | ||||
|   * data-unlock-sel | ||||
| - shm-clink = a link to a comment, flash the target element when clicked | ||||
|   * data-clink-sel | ||||
| 
 | ||||
| Documentation: http://shimmie.shishnet.org/doc/ | ||||
| 
 | ||||
| Please tell me if those docs are lacking in any way, so that they can be | ||||
| improved for the next person who uses them | ||||
| 
 | ||||
| 
 | ||||
| # Contact | ||||
| 
 | ||||
| IRC: `#shimmie` on [Freenode](irc.freenode.net) | ||||
| 
 | ||||
| Email: webmaster at shishnet.org | ||||
| 
 | ||||
| Issue/Bug tracker: http://github.com/shish/shimmie2/issues | ||||
| 
 | ||||
| 
 | ||||
| # Licence | ||||
| 
 | ||||
| All code is released under the [GNU GPL Version 2](http://www.gnu.org/licenses/gpl-2.0.html) unless mentioned otherwise. | ||||
| 
 | ||||
| If you give shimmie to someone else, you have to give them the source (which should be easy, as PHP | ||||
| is an interpreted language...). If you want to add customisations to your own | ||||
| site, then those customisations belong to you, and you can do what you want | ||||
| with them. | ||||
							
								
								
									
										133
									
								
								README.txt
									
									
									
									
									
								
							
							
						
						
									
										133
									
								
								README.txt
									
									
									
									
									
								
							| @ -1,133 +0,0 @@ | ||||
| 
 | ||||
|      _________.__     .__                   .__         ________    | ||||
|     /   _____/|  |__  |__|  _____    _____  |__|  ____  \_____  \   | ||||
|     \_____  \ |  |  \ |  | /     \  /     \ |  |_/ __ \  /  ____/   | ||||
|     /        \|   Y  \|  ||  Y Y  \|  Y Y  \|  |\  ___/ /       \   | ||||
|    /_______  /|___|  /|__||__|_|  /|__|_|  /|__| \___  >\_______ \  | ||||
|            \/      \/           \/       \/          \/         \/  | ||||
|                                                                  | ||||
| _________________________________________________________________________ | ||||
| 
 | ||||
| 
 | ||||
| Shimmie Development | ||||
| ~~~~~~~~~~~~~~~~~~~ | ||||
| This is the main branch of Shimmie, if you know anything at all about | ||||
| running websites, this is the version to use. Alternatively if you want | ||||
| a version that will never have significant changes, check out one of the | ||||
| versioned branches. | ||||
| 
 | ||||
| 
 | ||||
| Requirements | ||||
| ~~~~~~~~~~~~ | ||||
| MySQL/MariaDB 5.1+ (with experimental support for PostgreSQL 8+ and SQLite 3) | ||||
| PHP 5.3+ | ||||
| GD or ImageMagick | ||||
| 
 | ||||
| 
 | ||||
| Installation | ||||
| ~~~~~~~~~~~~ | ||||
| 1) Create a blank database | ||||
| 2) Unzip shimmie into a folder on the web host | ||||
| 3) Visit the folder with a web browser | ||||
| 4) Enter the location of the database | ||||
| 5) Click "install". Hopefully you'll end up at the welcome screen; if | ||||
|    not, you should be given instructions on how to fix any errors~ | ||||
| 
 | ||||
| 
 | ||||
| Upgrade from 2.3.X | ||||
| ~~~~~~~~~~~~~~~~~~ | ||||
| - Backup your current files and database! | ||||
| - Unzip into a clean folder | ||||
| - Copy across the images, thumbs, and data folders | ||||
| - Move old/config.php to new/data/config/shimmie.conf.php | ||||
| - Edit shimmie.conf.php to use the new database connection format: | ||||
| 
 | ||||
|  OLD: $database_dsn = "<proto>://<username>:<password>@<host>/<database>"; | ||||
|  NEW: define("DATABASE_DSN", "<proto>:user=<username>;password=<password>;host=<host>;dbname=<database>"); | ||||
| 
 | ||||
| The rest should be automatic~ | ||||
| 
 | ||||
| If there are any errors with the upgrade process, "in_upgrade=true" will | ||||
| be left in the config table and the process will be paused for the admin | ||||
| to investigate. Deleting this config entry and refreshing the page should | ||||
| continue the upgrade from where it left off. | ||||
| 
 | ||||
| 
 | ||||
| Upgrade from earlier versions | ||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||
| I very much recommend going via each major release in turn (eg, 2.0.6 | ||||
| -> 2.1.3 -> 2.2.4 -> 2.3.0 rather than 2.0.6 -> 2.3.0). While the basic | ||||
| database and file formats haven't changed *completely*, it's different | ||||
| enough to be a pain. | ||||
| 
 | ||||
| 
 | ||||
| Custom Configuration | ||||
| ~~~~~~~~~~~~~~~~~~~~ | ||||
| Various aspects of Shimmie can be configured to suit your site specific needs | ||||
| via the file "data/config/shimmie.conf.php" (created after installation). | ||||
| Take a look at "core/sys_config.inc.php" for the available options that can | ||||
| be used. | ||||
| 
 | ||||
| 
 | ||||
| Custom User Classes | ||||
| ~~~~~~~~~~~~~~~~~~~ | ||||
| User classes can be added to or altered by placing them in | ||||
| `data/config/user-classes.conf.php`. For example, one can override the | ||||
| default anonymous "allow nothing" permissions like so: | ||||
| 
 | ||||
| new UserClass("anonymous", "base", array( | ||||
| 	"create_comment" => True, | ||||
| 	"edit_image_tag" => True, | ||||
| 	"edit_image_source" => True, | ||||
| 	"create_image_report" => True, | ||||
| )); | ||||
| 
 | ||||
| For a moderator class, being a regular user who can delete images and | ||||
| comments: | ||||
| 
 | ||||
| new UserClass("moderator", "user", array( | ||||
| 	"delete_image" => True, | ||||
| 	"delete_comment" => True, | ||||
| )); | ||||
| 
 | ||||
| For a list of permissions, see core/userclass.class.php | ||||
| 
 | ||||
| 
 | ||||
| Development Info | ||||
| ~~~~~~~~~~~~~~~~ | ||||
| ui-* cookies are for the client-side scripts only; in some configurations | ||||
| (eg with varnish cache) they will be stripped before they reach the server | ||||
| 
 | ||||
| shm-* CSS classes are for javascript to hook into; if you're customising | ||||
| themes, be careful with these, and avoid styling them, eg: | ||||
| 
 | ||||
| - shm-thumb = outermost element of a thumbnail | ||||
|    - data-tags | ||||
|    - data-post-id | ||||
| - shm-toggler = click this to toggle elements that match the selector | ||||
|   - data-toggle-sel | ||||
| - shm-unlocker = click this to unlock elements that match the selector | ||||
|   - data-unlock-sel | ||||
| - shm-clink = a link to a comment, flash the target element when clicked | ||||
|   - data-clink-sel | ||||
| 
 | ||||
| http://shimmie.shishnet.org/doc/ | ||||
| 
 | ||||
| Please tell me if those docs are lacking in any way, so that they can be | ||||
| improved for the next person who uses them | ||||
| 
 | ||||
| 
 | ||||
| Contact | ||||
| ~~~~~~~ | ||||
| #shimmie on Freenode -- IRC | ||||
| webmaster at shishnet.org -- email | ||||
| https://github.com/shish/shimmie2/issues -- bug tracker | ||||
| 
 | ||||
| 
 | ||||
| Licence | ||||
| ~~~~~~~ | ||||
| All code is GPLv2 unless mentioned otherwise; ie, if you give shimmie to | ||||
| someone else, you have to give them the source (which should be easy, as PHP | ||||
| is an interpreted language...). If you want to add customisations to your own | ||||
| site, then those customisations belong to you, and you can do what you want | ||||
| with them. | ||||
| @ -56,7 +56,7 @@ class BaseThemelet { | ||||
| 		$h_tip = html_escape($image->get_tooltip()); | ||||
| 		$h_tags = strtolower($image->get_tag_list()); | ||||
| 
 | ||||
| 		$extArr = array_flip(array('swf', 'svg', 'mp4', 'ogv', 'webm', 'flv')); //List of thumbless filetypes
 | ||||
| 		$extArr = array_flip(array('swf', 'svg')); //List of thumbless filetypes
 | ||||
| 		if(!isset($extArr[$image->ext])){ | ||||
| 			$tsize = get_thumbnail_size($image->width, $image->height); | ||||
| 		}else{ | ||||
|  | ||||
| @ -1,17 +1,20 @@ | ||||
| <?php | ||||
| 
 | ||||
| /** | ||||
|  * A basic chunk of a page | ||||
|  * Class Block | ||||
|  * | ||||
|  * A basic chunk of a page. | ||||
|  */ | ||||
| class Block { | ||||
| 	/** | ||||
| 	 * The block's title | ||||
| 	 * The block's title. | ||||
| 	 * | ||||
| 	 * @var string | ||||
| 	 */ | ||||
| 	public $header; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * The content | ||||
| 	 * The content of the block. | ||||
| 	 * | ||||
| 	 * @var string | ||||
| 	 */ | ||||
| @ -19,7 +22,7 @@ class Block { | ||||
| 
 | ||||
| 	/**  | ||||
| 	 * Where the block should be placed. The default theme supports | ||||
| 	 * "main" and "left", other themes can add their own areas | ||||
| 	 * "main" and "left", other themes can add their own areas. | ||||
| 	 * | ||||
| 	 * @var string | ||||
| 	 */ | ||||
| @ -35,7 +38,9 @@ class Block { | ||||
| 	public $position; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @var int | ||||
| 	 * A unique ID for the block. | ||||
| 	 * | ||||
| 	 * @var string | ||||
| 	 */ | ||||
| 	public $id; | ||||
| 
 | ||||
| @ -46,7 +51,7 @@ class Block { | ||||
| 	 * @param string $body | ||||
| 	 * @param string $section | ||||
| 	 * @param int $position | ||||
| 	 * @param null|int $id | ||||
| 	 * @param null|int $id A unique ID for the block (generated automatically if null). | ||||
| 	 */ | ||||
| 	public function __construct($header, $body, /*string*/ $section="main", /*int*/ $position=50, $id=null) { | ||||
| 		$this->header = $header; | ||||
| @ -77,9 +82,12 @@ class Block { | ||||
| 
 | ||||
| 
 | ||||
| /** | ||||
|  * Class NavBlock | ||||
|  * | ||||
|  * A generic navigation block with a link to the main page. | ||||
|  * | ||||
|  * Used because "new NavBlock()" is easier than "new Block('Navigation', ..." | ||||
|  * | ||||
|  */ | ||||
| class NavBlock extends Block { | ||||
| 	public function __construct() { | ||||
|  | ||||
| @ -1,94 +1,237 @@ | ||||
| <?php | ||||
| 
 | ||||
| /** | ||||
|  * an abstract interface for altering a name:value pair list | ||||
|  * Interface Config | ||||
|  * | ||||
|  * An abstract interface for altering a name:value pair list. | ||||
|  */ | ||||
| interface Config { | ||||
| 	/** | ||||
| 	 * Save the list of name:value pairs to wherever they came from, | ||||
| 	 * so that the next time a page is loaded it will use the new | ||||
| 	 * configuration | ||||
| 	 * configuration. | ||||
| 	 * | ||||
| 	 * @param null|string $name | ||||
| 	 * @return mixed|void | ||||
| 	 */ | ||||
| 	public function save(/*string*/ $name=null); | ||||
| 
 | ||||
| 	/** @name set_* | ||||
| 	 * Set a configuration option to a new value, regardless | ||||
| 	 * of what the value is at the moment | ||||
| 	//@{ /*--------------------------------- SET ------------------------------------------------------*/
 | ||||
| 	/** | ||||
| 	 * Set a configuration option to a new value, regardless of what the value is at the moment. | ||||
| 	 * @param string $name | ||||
| 	 * @param null|int $value | ||||
| 	 * @return void | ||||
| 	 */ | ||||
| 	//@{
 | ||||
| 	public function set_int(/*string*/ $name, $value); | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Set a configuration option to a new value, regardless of what the value is at the moment. | ||||
| 	 * @param string $name | ||||
| 	 * @param null|string $value | ||||
| 	 * @return void | ||||
| 	 */ | ||||
| 	public function set_string(/*string*/ $name, $value); | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Set a configuration option to a new value, regardless of what the value is at the moment. | ||||
| 	 * @param string $name | ||||
| 	 * @param null|bool|string $value | ||||
| 	 * @return void | ||||
| 	 */ | ||||
| 	public function set_bool(/*string*/ $name, $value); | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Set a configuration option to a new value, regardless of what the value is at the moment. | ||||
| 	 * @param string $name | ||||
| 	 * @param array $value | ||||
| 	 * @return void | ||||
| 	 */ | ||||
| 	public function set_array(/*string*/ $name, $value); | ||||
| 	//@}
 | ||||
| 	//@} /*--------------------------------------------------------------------------------------------*/
 | ||||
| 
 | ||||
| 	/** @name set_default_* | ||||
| 	 * Set a configuration option to a new value, if there is no | ||||
| 	 * value currently. Extensions should generally call these | ||||
| 	 * from their InitExtEvent handlers. This has the advantage | ||||
| 	 * that the values will show up in the "advanced" setup page | ||||
| 	 * where they can be modified, while calling get_* with a | ||||
| 	 * "default" paramater won't show up. | ||||
| 	//@{ /*-------------------------------- SET DEFAULT -----------------------------------------------*/
 | ||||
| 	/** | ||||
| 	 * Set a configuration option to a new value, if there is no value currently. | ||||
| 	 * | ||||
| 	 * Extensions should generally call these from their InitExtEvent handlers. | ||||
| 	 * This has the advantage that the values will show up in the "advanced" setup | ||||
| 	 * page where they can be modified, while calling get_* with a "default" | ||||
| 	 * parameter won't show up. | ||||
| 	 * | ||||
| 	 * @param string $name | ||||
| 	 * @param int $value | ||||
| 	 * @return void | ||||
| 	 */ | ||||
| 	//@{
 | ||||
| 	public function set_default_int(/*string*/ $name, $value); | ||||
| 	public function set_default_string(/*string*/ $name, $value); | ||||
| 	public function set_default_bool(/*string*/ $name, $value); | ||||
| 	public function set_default_array(/*string*/ $name, $value); | ||||
| 	//@}
 | ||||
| 
 | ||||
| 	/** @name get_* | ||||
| 	 * pick a value out of the table by name, cast to the | ||||
| 	 * appropritate data type | ||||
| 	/** | ||||
| 	 * Set a configuration option to a new value, if there is no value currently. | ||||
| 	 * | ||||
| 	 * Extensions should generally call these from their InitExtEvent handlers. | ||||
| 	 * This has the advantage that the values will show up in the "advanced" setup | ||||
| 	 * page where they can be modified, while calling get_* with a "default" | ||||
| 	 * parameter won't show up. | ||||
| 	 * | ||||
| 	 * @param string $name | ||||
| 	 * @param string|null $value | ||||
| 	 * @return void | ||||
| 	 */ | ||||
| 	public function set_default_string(/*string*/ $name, $value); | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Set a configuration option to a new value, if there is no value currently. | ||||
| 	 * | ||||
| 	 * Extensions should generally call these from their InitExtEvent handlers. | ||||
| 	 * This has the advantage that the values will show up in the "advanced" setup | ||||
| 	 * page where they can be modified, while calling get_* with a "default" | ||||
| 	 * parameter won't show up. | ||||
| 	 * | ||||
| 	 * @param string $name | ||||
| 	 * @param bool|string|null $value | ||||
| 	 * @return void | ||||
| 	 */ | ||||
| 	public function set_default_bool(/*string*/ $name, $value); | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Set a configuration option to a new value, if there is no value currently. | ||||
| 	 * | ||||
| 	 * Extensions should generally call these from their InitExtEvent handlers. | ||||
| 	 * This has the advantage that the values will show up in the "advanced" setup | ||||
| 	 * page where they can be modified, while calling get_* with a "default" | ||||
| 	 * parameter won't show up. | ||||
| 	 * | ||||
| 	 * @param string $name | ||||
| 	 * @param array $value | ||||
| 	 * @return void | ||||
| 	 */ | ||||
| 	public function set_default_array(/*string*/ $name, $value); | ||||
| 	//@} /*--------------------------------------------------------------------------------------------*/
 | ||||
| 
 | ||||
| 	//@{ /*--------------------------------- GET ------------------------------------------------------*/
 | ||||
| 	/** | ||||
| 	 * Pick a value out of the table by name, cast to the appropriate data type. | ||||
| 	 * @param string $name | ||||
| 	 * @param null|int $default | ||||
| 	 * @return int | ||||
| 	 */ | ||||
| 	//@{
 | ||||
| 	public function get_int(/*string*/ $name, $default=null); | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Pick a value out of the table by name, cast to the appropriate data type. | ||||
| 	 * @param string $name | ||||
| 	 * @param null|string $default | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	public function get_string(/*string*/ $name, $default=null); | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Pick a value out of the table by name, cast to the appropriate data type. | ||||
| 	 * @param string $name | ||||
| 	 * @param null|bool|string $default | ||||
| 	 * @return bool | ||||
| 	 */ | ||||
| 	public function get_bool(/*string*/ $name, $default=null); | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Pick a value out of the table by name, cast to the appropriate data type. | ||||
| 	 * @param string $name | ||||
| 	 * @param array|null $default | ||||
| 	 * @return array | ||||
| 	 */ | ||||
| 	public function get_array(/*string*/ $name, $default=array()); | ||||
| 	//@}
 | ||||
| 	//@} /*--------------------------------------------------------------------------------------------*/
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /** | ||||
|  * Class BaseConfig | ||||
|  * | ||||
|  * Common methods for manipulating the list, loading and saving is | ||||
|  * left to the concrete implementation | ||||
|  */ | ||||
| abstract class BaseConfig implements Config { | ||||
| 	var $values = array(); | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $name | ||||
| 	 * @param int|null $value | ||||
| 	 * @return void | ||||
| 	 */ | ||||
| 	public function set_int(/*string*/ $name, $value) { | ||||
| 		$this->values[$name] = parse_shorthand_int($value); | ||||
| 		$this->save($name); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $name | ||||
| 	 * @param null|string $value | ||||
| 	 * @return void | ||||
| 	 */ | ||||
| 	public function set_string(/*string*/ $name, $value) { | ||||
| 		$this->values[$name] = $value; | ||||
| 		$this->save($name); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $name | ||||
| 	 * @param bool|null|string $value | ||||
| 	 * @return void | ||||
| 	 */ | ||||
| 	public function set_bool(/*string*/ $name, $value) { | ||||
| 		$this->values[$name] = (($value == 'on' || $value === true) ? 'Y' : 'N'); | ||||
| 		$this->save($name); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $name | ||||
| 	 * @param array $value | ||||
| 	 * @return void | ||||
| 	 */ | ||||
| 	public function set_array(/*string*/ $name, $value) { | ||||
| 		assert(isset($value) && is_array($value)); | ||||
| 		$this->values[$name] = implode(",", $value); | ||||
| 		$this->save($name); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $name | ||||
| 	 * @param int $value | ||||
| 	 * @return void | ||||
| 	 */ | ||||
| 	public function set_default_int(/*string*/ $name, $value) { | ||||
| 		if(is_null($this->get($name))) { | ||||
| 			$this->values[$name] = parse_shorthand_int($value); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $name | ||||
| 	 * @param null|string $value | ||||
| 	 * @return void | ||||
| 	 */ | ||||
| 	public function set_default_string(/*string*/ $name, $value) { | ||||
| 		if(is_null($this->get($name))) { | ||||
| 			$this->values[$name] = $value; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $name | ||||
| 	 * @param bool|null|string $value | ||||
| 	 * @return void | ||||
| 	 */ | ||||
| 	public function set_default_bool(/*string*/ $name, $value) { | ||||
| 		if(is_null($this->get($name))) { | ||||
| 			$this->values[$name] = (($value == 'on' || $value === true) ? 'Y' : 'N'); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $name | ||||
| 	 * @param array $value | ||||
| 	 * @return void | ||||
| 	 */ | ||||
| 	public function set_default_array(/*string*/ $name, $value) { | ||||
| 		assert(isset($value) && is_array($value)); | ||||
| 		if(is_null($this->get($name))) { | ||||
| @ -96,19 +239,47 @@ abstract class BaseConfig implements Config { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $name | ||||
| 	 * @param null|int $default | ||||
| 	 * @return int | ||||
| 	 */ | ||||
| 	public function get_int(/*string*/ $name, $default=null) { | ||||
| 		return (int)($this->get($name, $default)); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $name | ||||
| 	 * @param null|string $default | ||||
| 	 * @return null|string | ||||
| 	 */ | ||||
| 	public function get_string(/*string*/ $name, $default=null) { | ||||
| 		return $this->get($name, $default); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $name | ||||
| 	 * @param null|bool|string $default | ||||
| 	 * @return bool | ||||
| 	 */ | ||||
| 	public function get_bool(/*string*/ $name, $default=null) { | ||||
| 		return bool_escape($this->get($name, $default)); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $name | ||||
| 	 * @param array $default | ||||
| 	 * @return array | ||||
| 	 */ | ||||
| 	public function get_array(/*string*/ $name, $default=array()) { | ||||
| 		return explode(",", $this->get($name, "")); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $name | ||||
| 	 * @param null|mixed $default | ||||
| 	 * @return null|mixed | ||||
| 	 */ | ||||
| 	private function get(/*string*/ $name, $default=null) { | ||||
| 		if(isset($this->values[$name])) { | ||||
| 			return $this->values[$name]; | ||||
| @ -121,13 +292,19 @@ abstract class BaseConfig implements Config { | ||||
| 
 | ||||
| 
 | ||||
| /** | ||||
|  * For testing, mostly | ||||
|  * Class HardcodeConfig | ||||
|  * | ||||
|  * For testing, mostly. | ||||
|  */ | ||||
| class HardcodeConfig extends BaseConfig { | ||||
| 	public function __construct($dict) { | ||||
| 		$this->values = $dict; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param null|string $name | ||||
| 	 * @return mixed|void | ||||
| 	 */ | ||||
| 	public function save(/*string*/ $name=null) { | ||||
| 		// static config is static
 | ||||
| 	} | ||||
| @ -135,6 +312,8 @@ class HardcodeConfig extends BaseConfig { | ||||
| 
 | ||||
| 
 | ||||
| /** | ||||
|  * Class StaticConfig | ||||
|  * | ||||
|  * Loads the config list from a PHP file; the file should be in the format: | ||||
|  * | ||||
|  *  <?php | ||||
| @ -143,6 +322,10 @@ class HardcodeConfig extends BaseConfig { | ||||
|  *  ?>
 | ||||
|  */ | ||||
| class StaticConfig extends BaseConfig { | ||||
| 	/** | ||||
| 	 * @param string $filename | ||||
| 	 * @throws Exception | ||||
| 	 */ | ||||
| 	public function __construct($filename) { | ||||
| 		if(file_exists($filename)) { | ||||
| 			require_once $filename; | ||||
| @ -158,6 +341,10 @@ class StaticConfig extends BaseConfig { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param null|string $name | ||||
| 	 * @return mixed|void | ||||
| 	 */ | ||||
| 	public function save(/*string*/ $name=null) { | ||||
| 		// static config is static
 | ||||
| 	} | ||||
| @ -165,6 +352,8 @@ class StaticConfig extends BaseConfig { | ||||
| 
 | ||||
| 
 | ||||
| /** | ||||
|  * Class DatabaseConfig | ||||
|  * | ||||
|  * Loads the config list from a table in a given database, the table should | ||||
|  * be called config and have the schema: | ||||
|  * | ||||
| @ -176,10 +365,13 @@ class StaticConfig extends BaseConfig { | ||||
|  * \endcode | ||||
|  */ | ||||
| class DatabaseConfig extends BaseConfig { | ||||
| 	/** @var \Database|null  */ | ||||
| 	var $database = null; | ||||
| 
 | ||||
| 	/* | ||||
| 	 * Load the config table from a database | ||||
| 	/** | ||||
| 	 * Load the config table from a database. | ||||
| 	 * | ||||
| 	 * @param Database $database | ||||
| 	 */ | ||||
| 	public function __construct(Database $database) { | ||||
| 		$this->database = $database; | ||||
| @ -197,8 +389,11 @@ class DatabaseConfig extends BaseConfig { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/* | ||||
| 	 * Save the current values as the new config table | ||||
| 	/** | ||||
| 	 * Save the current values as the new config table. | ||||
| 	 * | ||||
| 	 * @param null|string $name | ||||
| 	 * @return mixed|void | ||||
| 	 */ | ||||
| 	public function save(/*string*/ $name=null) { | ||||
| 		if(is_null($name)) { | ||||
| @ -217,7 +412,13 @@ class DatabaseConfig extends BaseConfig { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Class MockConfig | ||||
|  */ | ||||
| class MockConfig extends HardcodeConfig { | ||||
| 	/** | ||||
| 	 * @param array $config | ||||
| 	 */ | ||||
| 	public function __construct($config=array()) { | ||||
| 		$config["db_version"] = "999"; | ||||
| 		$config["anon_id"] = "0"; | ||||
|  | ||||
| @ -2,41 +2,70 @@ | ||||
| /** @privatesection */ | ||||
| // Querylet {{{
 | ||||
| class Querylet { | ||||
| 	var $sql; | ||||
| 	var $variables; | ||||
| 	/** @var string */ | ||||
| 	public $sql; | ||||
| 	/** @var array */ | ||||
| 	public $variables; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $sql | ||||
| 	 * @param array $variables | ||||
| 	 */ | ||||
| 	public function __construct($sql, $variables=array()) { | ||||
| 		$this->sql = $sql; | ||||
| 		$this->variables = $variables; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param \Querylet $querylet | ||||
| 	 */ | ||||
| 	public function append($querylet) { | ||||
| 		assert(!is_null($querylet)); | ||||
| 		$this->sql .= $querylet->sql; | ||||
| 		$this->variables = array_merge($this->variables, $querylet->variables); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $sql | ||||
| 	 */ | ||||
| 	public function append_sql($sql) { | ||||
| 		$this->sql .= $sql; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param mixed $var | ||||
| 	 */ | ||||
| 	public function add_variable($var) { | ||||
| 		$this->variables[] = $var; | ||||
| 	} | ||||
| } | ||||
| class TagQuerylet { | ||||
| 	var $tag; | ||||
| 	var $positive; | ||||
| 
 | ||||
| class TagQuerylet { | ||||
| 	/** @var string  */ | ||||
| 	public $tag; | ||||
| 	/** @var bool  */ | ||||
| 	public $positive; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $tag | ||||
| 	 * @param bool $positive | ||||
| 	 */ | ||||
| 	public function __construct($tag, $positive) { | ||||
| 		$this->tag = $tag; | ||||
| 		$this->positive = $positive; | ||||
| 	} | ||||
| } | ||||
| class ImgQuerylet { | ||||
| 	var $qlet; | ||||
| 	var $positive; | ||||
| 
 | ||||
| class ImgQuerylet { | ||||
| 	/** @var \Querylet */ | ||||
| 	public $qlet; | ||||
| 	/** @var bool */ | ||||
| 	public $positive; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param \Querylet $qlet | ||||
| 	 * @param bool $positive | ||||
| 	 */ | ||||
| 	public function __construct($qlet, $positive) { | ||||
| 		$this->qlet = $qlet; | ||||
| 		$this->positive = $positive; | ||||
| @ -45,25 +74,46 @@ class ImgQuerylet { | ||||
| // }}}
 | ||||
| // {{{ db engines
 | ||||
| class DBEngine { | ||||
| 	/** @var null|string */ | ||||
| 	public $name = null; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param \PDO $db | ||||
| 	 */ | ||||
| 	public function init($db) {} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $scoreql | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	public function scoreql_to_sql($scoreql) { | ||||
| 		return $scoreql; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $name | ||||
| 	 * @param string $data | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	public function create_table_sql($name, $data) { | ||||
| 		return 'CREATE TABLE '.$name.' ('.$data.')'; | ||||
| 	} | ||||
| } | ||||
| class MySQL extends DBEngine { | ||||
| 	/** @var string */ | ||||
| 	public $name = "mysql"; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param \PDO $db | ||||
| 	 */ | ||||
| 	public function init($db) { | ||||
| 		$db->exec("SET NAMES utf8;"); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $data | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	public function scoreql_to_sql($data) { | ||||
| 		$data = str_replace("SCORE_AIPK", "INTEGER PRIMARY KEY auto_increment", $data); | ||||
| 		$data = str_replace("SCORE_INET", "VARCHAR(45)", $data); | ||||
| @ -77,6 +127,11 @@ class MySQL extends DBEngine { | ||||
| 		return $data; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $name | ||||
| 	 * @param string $data | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	public function create_table_sql($name, $data) { | ||||
| 		$data = $this->scoreql_to_sql($data); | ||||
| 		$ctes = "ENGINE=InnoDB DEFAULT CHARSET='utf8'"; | ||||
| @ -84,12 +139,20 @@ class MySQL extends DBEngine { | ||||
| 	} | ||||
| } | ||||
| class PostgreSQL extends DBEngine { | ||||
| 	/** @var string */ | ||||
| 	public $name = "pgsql"; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param \PDO $db | ||||
| 	 */ | ||||
| 	public function init($db) { | ||||
| 		$db->exec("SET application_name TO 'shimmie [{$_SERVER['REMOTE_ADDR']}]';"); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $data | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	public function scoreql_to_sql($data) { | ||||
| 		$data = str_replace("SCORE_AIPK", "SERIAL PRIMARY KEY", $data); | ||||
| 		$data = str_replace("SCORE_INET", "INET", $data); | ||||
| @ -103,6 +166,11 @@ class PostgreSQL extends DBEngine { | ||||
| 		return $data; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $name | ||||
| 	 * @param string $data | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	public function create_table_sql($name, $data) { | ||||
| 		$data = $this->scoreql_to_sql($data); | ||||
| 		return 'CREATE TABLE '.$name.' ('.$data.')'; | ||||
| @ -123,8 +191,12 @@ function _concat($a, $b) { return $a . $b; } | ||||
| function _lower($a) { return strtolower($a); } | ||||
| 
 | ||||
| class SQLite extends DBEngine { | ||||
| 	/** @var string  */ | ||||
| 	public $name = "sqlite"; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param \PDO $db | ||||
| 	 */ | ||||
| 	public function init($db) { | ||||
| 		ini_set('sqlite.assoc_case', 0); | ||||
| 		$db->exec("PRAGMA foreign_keys = ON;"); | ||||
| @ -138,6 +210,10 @@ class SQLite extends DBEngine { | ||||
| 		$db->sqliteCreateFunction('lower', '_lower', 1); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $data | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	public function scoreql_to_sql($data) { | ||||
| 		$data = str_replace("SCORE_AIPK", "INTEGER PRIMARY KEY", $data); | ||||
| 		$data = str_replace("SCORE_INET", "VARCHAR(45)", $data); | ||||
| @ -150,6 +226,11 @@ class SQLite extends DBEngine { | ||||
| 		return $data; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $name | ||||
| 	 * @param string $data | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	public function create_table_sql($name, $data) { | ||||
| 		$data = $this->scoreql_to_sql($data); | ||||
| 		$cols = array(); | ||||
| @ -187,22 +268,38 @@ class NoCache implements CacheEngine { | ||||
| 	public function get_misses() {return 0;} | ||||
| } | ||||
| class MemcacheCache implements CacheEngine { | ||||
| 	var $memcache=null, $hits=0, $misses=0; | ||||
| 	/** @var \Memcache|null */ | ||||
| 	public $memcache=null; | ||||
| 	/** @var int */ | ||||
| 	private $hits=0; | ||||
| 	/** @var int */ | ||||
| 	private $misses=0; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $args | ||||
| 	 */ | ||||
| 	public function __construct($args) { | ||||
| 		$hp = explode(":", $args); | ||||
| 		if(class_exists("Memcache")) { | ||||
| 			$this->memcache = new Memcache; | ||||
| 			@$this->memcache->pconnect($hp[0], $hp[1]); | ||||
| 		} | ||||
| 		else { | ||||
| 			print "no memcache"; exit; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $key | ||||
| 	 * @return array|bool|string | ||||
| 	 */ | ||||
| 	public function get($key) { | ||||
| 		assert(!is_null($key)); | ||||
| 		if((DEBUG_CACHE === true) || (is_null(DEBUG_CACHE) && @$_GET['DEBUG_CACHE'])) { | ||||
| 			file_put_contents("data/cache.log", "Cache lookup: $key\n", FILE_APPEND); | ||||
| 		} | ||||
| 		$val = $this->memcache->get($key); | ||||
| 		if((DEBUG_CACHE === true) || (is_null(DEBUG_CACHE) && @$_GET['DEBUG_CACHE'])) { | ||||
| 			$hit = $val === false ? "miss" : "hit"; | ||||
| 			file_put_contents("data/cache.log", "Cache $hit: $key\n", FILE_APPEND); | ||||
| 		} | ||||
| 		if($val !== false) { | ||||
| 			$this->hits++; | ||||
| 			return $val; | ||||
| @ -213,19 +310,35 @@ class MemcacheCache implements CacheEngine { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $key | ||||
| 	 * @param mixed $val | ||||
| 	 * @param int $time | ||||
| 	 */ | ||||
| 	public function set($key, $val, $time=0) { | ||||
| 		assert(!is_null($key)); | ||||
| 		$this->memcache->set($key, $val, false, $time); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $key | ||||
| 	 */ | ||||
| 	public function delete($key) { | ||||
| 		assert(!is_null($key)); | ||||
| 		$this->memcache->delete($key); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @return int | ||||
| 	 */ | ||||
| 	public function get_hits() {return $this->hits;} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @return int | ||||
| 	 */ | ||||
| 	public function get_misses() {return $this->misses;} | ||||
| } | ||||
| 
 | ||||
| class APCCache implements CacheEngine { | ||||
| 	var $hits=0, $misses=0; | ||||
| 
 | ||||
| @ -267,25 +380,29 @@ class APCCache implements CacheEngine { | ||||
|  */ | ||||
| class Database { | ||||
| 	/** | ||||
| 	 * The PDO database connection object, for anyone who wants direct access | ||||
| 	 * The PDO database connection object, for anyone who wants direct access. | ||||
| 	 * @var null|PDO | ||||
| 	 */ | ||||
| 	private $db = null; | ||||
| 	public $dbtime = 0.0; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Meta info about the database engine | ||||
| 	 * @var DBEngine | ||||
| 	 * Meta info about the database engine. | ||||
| 	 * @var DBEngine|null | ||||
| 	 */ | ||||
| 	private $engine = null; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * The currently active cache engine | ||||
| 	 * @var CacheEngine | ||||
| 	 * The currently active cache engine. | ||||
| 	 * @var CacheEngine|null | ||||
| 	 */ | ||||
| 	public $cache = null; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * A boolean flag to track if we already have an active transaction. | ||||
| 	 * (ie: True if beginTransaction() already called) | ||||
| 	 * | ||||
| 	 * @var bool | ||||
| 	 */ | ||||
| 	public $transaction = false; | ||||
| 
 | ||||
| @ -364,6 +481,10 @@ class Database { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @return bool | ||||
| 	 * @throws SCoreException | ||||
| 	 */ | ||||
| 	public function commit() { | ||||
| 		if(!is_null($this->db)) { | ||||
| 			if ($this->transaction === true) { | ||||
| @ -376,6 +497,10 @@ class Database { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @return bool | ||||
| 	 * @throws SCoreException | ||||
| 	 */ | ||||
| 	public function rollback() { | ||||
| 		if(!is_null($this->db)) { | ||||
| 			if ($this->transaction === true) { | ||||
| @ -388,23 +513,39 @@ class Database { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $input | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	public function escape($input) { | ||||
| 		if(is_null($this->db)) $this->connect_db(); | ||||
| 		return $this->db->Quote($input); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $input | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	public function scoreql_to_sql($input) { | ||||
| 		if(is_null($this->engine)) $this->connect_engine(); | ||||
| 		return $this->engine->scoreql_to_sql($input); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @return null|string | ||||
| 	 */ | ||||
| 	public function get_driver_name() { | ||||
| 		if(is_null($this->engine)) $this->connect_engine(); | ||||
| 		return $this->engine->name; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Execute an SQL query and return an PDO resultset | ||||
| 	 * Execute an SQL query and return an PDO result-set. | ||||
| 	 * | ||||
| 	 * @param string $query | ||||
| 	 * @param array $args | ||||
| 	 * @return PDOStatement | ||||
| 	 * @throws SCoreException | ||||
| 	 */ | ||||
| 	public function execute($query, $args=array()) { | ||||
| 		try { | ||||
| @ -433,54 +574,88 @@ class Database { | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Execute an SQL query and return a 2D array | ||||
| 	 * Execute an SQL query and return a 2D array. | ||||
| 	 * | ||||
| 	 * @param string $query | ||||
| 	 * @param array $args | ||||
| 	 * @return array | ||||
| 	 */ | ||||
| 	public function get_all($query, $args=array()) { | ||||
| 		return $this->execute($query, $args)->fetchAll(); | ||||
| 		$_start = microtime(true); | ||||
| 		$data = $this->execute($query, $args)->fetchAll(); | ||||
| 		$this->dbtime += microtime(true) - $_start; | ||||
| 		return $data; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Execute an SQL query and return a single row | ||||
| 	 * Execute an SQL query and return a single row. | ||||
| 	 * | ||||
| 	 * @param string $query | ||||
| 	 * @param array $args | ||||
| 	 * @return mixed|null | ||||
| 	 */ | ||||
| 	public function get_row($query, $args=array()) { | ||||
| 		$_start = microtime(true); | ||||
| 		$row = $this->execute($query, $args)->fetch(); | ||||
| 		$this->dbtime += microtime(true) - $_start; | ||||
| 		return $row ? $row : null; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Execute an SQL query and return the first column of each row | ||||
| 	 * Execute an SQL query and return the first column of each row. | ||||
| 	 * | ||||
| 	 * @param string $query | ||||
| 	 * @param array $args | ||||
| 	 * @return array | ||||
| 	 */ | ||||
| 	public function get_col($query, $args=array()) { | ||||
| 		$_start = microtime(true); | ||||
| 		$stmt = $this->execute($query, $args); | ||||
| 		$res = array(); | ||||
| 		foreach($stmt as $row) { | ||||
| 			$res[] = $row[0]; | ||||
| 		} | ||||
| 		$this->dbtime += microtime(true) - $_start; | ||||
| 		return $res; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Execute an SQL query and return the the first row => the second rown | ||||
| 	 * Execute an SQL query and return the the first row => the second rown. | ||||
| 	 * | ||||
| 	 * @param string $query | ||||
| 	 * @param array $args | ||||
| 	 * @return array | ||||
| 	 */ | ||||
| 	public function get_pairs($query, $args=array()) { | ||||
| 		$_start = microtime(true); | ||||
| 		$stmt = $this->execute($query, $args); | ||||
| 		$res = array(); | ||||
| 		foreach($stmt as $row) { | ||||
| 			$res[$row[0]] = $row[1]; | ||||
| 		} | ||||
| 		$this->dbtime += microtime(true) - $_start; | ||||
| 		return $res; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Execute an SQL query and return a single value | ||||
| 	 * Execute an SQL query and return a single value. | ||||
| 	 * | ||||
| 	 * @param string $query | ||||
| 	 * @param array $args | ||||
| 	 * @return mixed | ||||
| 	 */ | ||||
| 	public function get_one($query, $args=array()) { | ||||
| 		$_start = microtime(true); | ||||
| 		$row = $this->execute($query, $args)->fetch(); | ||||
| 		$this->dbtime += microtime(true) - $_start; | ||||
| 		return $row[0]; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * get the ID of the last inserted row | ||||
| 	 * Get the ID of the last inserted row. | ||||
| 	 * | ||||
| 	 * @param string|null $seq | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	public function get_last_insert_id($seq) { | ||||
| 		if($this->engine->name == "pgsql") { | ||||
| @ -492,15 +667,20 @@ class Database { | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Create a table from pseudo-SQL | ||||
| 	 * Create a table from pseudo-SQL. | ||||
| 	 * | ||||
| 	 * @param string $name | ||||
| 	 * @param string $data | ||||
| 	 */ | ||||
| 	public function create_table($name, $data) { | ||||
| 		if(is_null($this->engine)) $this->connect_engine(); | ||||
| 		if(is_null($this->engine)) { $this->connect_engine(); } | ||||
| 		$this->execute($this->engine->create_table_sql($name, $data)); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Returns the number of tables present in the current database. | ||||
| 	 * | ||||
| 	 * @return int|null | ||||
| 	 */ | ||||
| 	public function count_tables() { | ||||
| 		if(is_null($this->db) || is_null($this->engine)) $this->connect_db(); | ||||
| @ -525,14 +705,26 @@ class Database { | ||||
| } | ||||
| 
 | ||||
| class MockDatabase extends Database { | ||||
| 	/** @var int */ | ||||
| 	var $query_id = 0; | ||||
| 	/** @var array */ | ||||
| 	var $responses = array(); | ||||
| 	/** @var \NoCache|null  */ | ||||
| 	var $cache = null; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param array $responses | ||||
| 	 */ | ||||
| 	public function __construct($responses = array()) { | ||||
| 		$this->cache = new NoCache(); | ||||
| 		$this->responses = $responses; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $query | ||||
| 	 * @param array $params | ||||
| 	 * @return PDOStatement | ||||
| 	 */ | ||||
| 	public function execute($query, $params=array()) { | ||||
| 		log_debug("mock-database", | ||||
| 			"QUERY: " . $query . | ||||
| @ -542,13 +734,51 @@ class MockDatabase extends Database { | ||||
| 		return $this->responses[$this->query_id++]; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $query | ||||
| 	 * @param array $args | ||||
| 	 * @return array|PDOStatement | ||||
| 	 */ | ||||
| 	public function get_all($query, $args=array()) {return $this->execute($query, $args);} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $query | ||||
| 	 * @param array $args | ||||
| 	 * @return mixed|null|PDOStatement | ||||
| 	 */ | ||||
| 	public function get_row($query, $args=array()) {return $this->execute($query, $args);} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $query | ||||
| 	 * @param array $args | ||||
| 	 * @return array|PDOStatement | ||||
| 	 */ | ||||
| 	public function get_col($query, $args=array()) {return $this->execute($query, $args);} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $query | ||||
| 	 * @param array $args | ||||
| 	 * @return array|PDOStatement | ||||
| 	 */ | ||||
| 	public function get_pairs($query, $args=array()) {return $this->execute($query, $args);} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $query | ||||
| 	 * @param array $args | ||||
| 	 * @return mixed|PDOStatement | ||||
| 	 */ | ||||
| 	public function get_one($query, $args=array()) {return $this->execute($query, $args);} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param null|string $seq | ||||
| 	 * @return int|string | ||||
| 	 */ | ||||
| 	public function get_last_insert_id($seq) {return $this->query_id;} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $sql | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	public function scoreql_to_sql($sql) {return $sql;} | ||||
| 	public function create_table($name, $def) {} | ||||
| 	public function connect_engine() {} | ||||
|  | ||||
| @ -1,21 +1,40 @@ | ||||
| <?php | ||||
| 
 | ||||
| class Email { | ||||
| 	/** | ||||
| /** | ||||
|  * Class Email | ||||
|  * | ||||
|  * A generic email. | ||||
|  */ | ||||
| class Email { | ||||
| 	/** @var string */ | ||||
| 	public $to; | ||||
| 	/** @var string  */ | ||||
| 	public $subject; | ||||
| 	/** @var string  */ | ||||
| 	public $header; | ||||
| 	/** @var null|string  */ | ||||
| 	public $style; | ||||
| 	/** @var null|string  */ | ||||
| 	public $header_img; | ||||
| 	/** @var null|string  */ | ||||
| 	public $sitename; | ||||
| 	/** @var null|string  */ | ||||
| 	public $sitedomain; | ||||
| 	/** @var null|string */ | ||||
| 	public $siteemail; | ||||
| 	/** @var string */ | ||||
| 	public $date; | ||||
| 	/** @var string */ | ||||
| 	public $body; | ||||
| 	/** @var null|string */ | ||||
| 	public $footer; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $to | ||||
| 	 * @param string $subject | ||||
| 	 * @param string $header | ||||
| 	 * @param string $body | ||||
| 	 */ | ||||
| 	public function __construct($to, $subject, $header, $body) { | ||||
| 		global $config; | ||||
| 		$this->to = $to; | ||||
|  | ||||
| @ -26,8 +26,19 @@ class InitExtEvent extends Event {} | ||||
|  * $event->get_arg(0) = "42" | ||||
|  */ | ||||
| class PageRequestEvent extends Event { | ||||
| 	/** | ||||
| 	 * @var array | ||||
| 	 */ | ||||
| 	public $args; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @var int | ||||
| 	 */ | ||||
| 	public $arg_count; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @var int | ||||
| 	 */ | ||||
| 	public $part_count; | ||||
| 
 | ||||
| 	/** | ||||
| @ -90,7 +101,7 @@ class PageRequestEvent extends Event { | ||||
| 	 * Get the n th argument of the page request (if it exists.) | ||||
| 	 * | ||||
| 	 * @param int $n | ||||
| 	 * @return string|null The argmuent (string) or NULL | ||||
| 	 * @return string|null The argument (string) or NULL | ||||
| 	 */ | ||||
| 	public function get_arg(/*int*/ $n) { | ||||
| 		$offset = $this->part_count + $n; | ||||
| @ -154,9 +165,19 @@ class PageRequestEvent extends Event { | ||||
|  * Sent when index.php is called from the command line | ||||
|  */ | ||||
| class CommandEvent extends Event { | ||||
| 	/** | ||||
| 	 * @var string | ||||
| 	 */ | ||||
| 	public $cmd = "help"; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @var array | ||||
| 	 */ | ||||
| 	public $args = array(); | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string[] $args | ||||
| 	 */ | ||||
| 	public function __construct(/*array(string)*/ $args) { | ||||
| 		global $user; | ||||
| 
 | ||||
| @ -215,19 +236,28 @@ class CommandEvent extends Event { | ||||
| class TextFormattingEvent extends Event { | ||||
| 	/** | ||||
| 	 * For reference | ||||
| 	 * | ||||
| 	 * @var string | ||||
| 	 */ | ||||
| 	var $original; | ||||
| 	public $original; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * with formatting applied | ||||
| 	 * | ||||
| 	 * @var string | ||||
| 	 */ | ||||
| 	var $formatted; | ||||
| 	public $formatted; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * with formatting removed | ||||
| 	 * | ||||
| 	 * @var string | ||||
| 	 */ | ||||
| 	var $stripped; | ||||
| 	public $stripped; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $text | ||||
| 	 */ | ||||
| 	public function __construct(/*string*/ $text) { | ||||
| 		$h_text = html_escape(trim($text)); | ||||
| 		$this->original  = $h_text; | ||||
| @ -244,36 +274,44 @@ class LogEvent extends Event { | ||||
| 	/** | ||||
| 	 * a category, normally the extension name | ||||
| 	 * | ||||
| 	 * @return string | ||||
| 	 * @var string | ||||
| 	 */ | ||||
| 	var $section; | ||||
| 	public $section; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * See python... | ||||
| 	 * | ||||
| 	 * @return int | ||||
| 	 * @var int | ||||
| 	 */ | ||||
| 	var $priority = 0; | ||||
| 	public $priority = 0; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Free text to be logged | ||||
| 	 * | ||||
| 	 * @return text | ||||
| 	 * @var string | ||||
| 	 */ | ||||
| 	var $message; | ||||
| 	public $message; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * The time that the event was created | ||||
| 	 * | ||||
| 	 * @return int | ||||
| 	 * @var int | ||||
| 	 */ | ||||
| 	var $time; | ||||
| 	public $time; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Extra data to be held separate | ||||
| 	 * | ||||
| 	 * @var array | ||||
| 	 */ | ||||
| 	var $args; | ||||
| 	public $args; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $section | ||||
| 	 * @param int $priority | ||||
| 	 * @param string $message | ||||
| 	 * @param array $args | ||||
| 	 */ | ||||
| 	public function __construct($section, $priority, $message, $args) { | ||||
| 		$this->section = $section; | ||||
| 		$this->priority = $priority; | ||||
|  | ||||
| @ -1,11 +1,16 @@ | ||||
| <?php | ||||
| 
 | ||||
| /** | ||||
|  * A base exception to be caught by the upper levels | ||||
|  * Class SCoreException | ||||
|  * | ||||
|  * A base exception to be caught by the upper levels. | ||||
|  */ | ||||
| class SCoreException extends Exception {} | ||||
| 
 | ||||
| /** | ||||
|  * A fairly common, generic exception | ||||
|  * Class PermissionDeniedException | ||||
|  * | ||||
|  * A fairly common, generic exception. | ||||
|  */ | ||||
| class PermissionDeniedException extends SCoreException {} | ||||
| 
 | ||||
|  | ||||
| @ -70,6 +70,8 @@ | ||||
|  */ | ||||
| 
 | ||||
| /** | ||||
|  * Class Extension | ||||
|  * | ||||
|  * send_event(BlahEvent()) -> onBlah($event) | ||||
|  * | ||||
|  * Also loads the theme object into $this->theme if available | ||||
| @ -96,7 +98,11 @@ abstract class Extension { | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Find the theme object for a given extension | ||||
| 	 * Find the theme object for a given extension. | ||||
| 	 * | ||||
| 	 * @param Extension $class | ||||
| 	 * @param bool $fatal | ||||
| 	 * @return bool | ||||
| 	 */ | ||||
| 	private function get_theme_object(Extension $class, $fatal=true) { | ||||
| 		$base = get_class($class); | ||||
| @ -114,7 +120,9 @@ abstract class Extension { | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Override this to change the priority of the extension, | ||||
| 	 * lower numbered ones will recieve events first | ||||
| 	 * lower numbered ones will recieve events first. | ||||
| 	 * | ||||
| 	 * @return int | ||||
| 	 */ | ||||
| 	public function get_priority() { | ||||
| 		return 50; | ||||
| @ -122,23 +130,43 @@ abstract class Extension { | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Several extensions have this in common, make a common API | ||||
|  * Class FormatterExtension | ||||
|  * | ||||
|  * Several extensions have this in common, make a common API. | ||||
|  */ | ||||
| abstract class FormatterExtension extends Extension { | ||||
| 	/** | ||||
| 	 * @param TextFormattingEvent $event | ||||
| 	 */ | ||||
| 	public function onTextFormatting(TextFormattingEvent $event) { | ||||
| 		$event->formatted = $this->format($event->formatted); | ||||
| 		$event->stripped  = $this->strip($event->stripped); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $text | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	abstract public function format(/*string*/ $text); | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $text | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	abstract public function strip(/*string*/ $text); | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Class DataHandlerExtension | ||||
|  * | ||||
|  * This too is a common class of extension with many methods in common, | ||||
|  * so we have a base class to extend from | ||||
|  * so we have a base class to extend from. | ||||
|  */ | ||||
| abstract class DataHandlerExtension extends Extension { | ||||
| 	/** | ||||
| 	 * @param DataUploadEvent $event | ||||
| 	 * @throws UploadException | ||||
| 	 */ | ||||
| 	public function onDataUpload(DataUploadEvent $event) { | ||||
| 		$supported_ext = $this->supported_ext($event->type); | ||||
| 		$check_contents = $this->check_contents($event->tmpname); | ||||
| @ -202,6 +230,9 @@ abstract class DataHandlerExtension extends Extension { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param ThumbnailGenerationEvent $event | ||||
| 	 */ | ||||
| 	public function onThumbnailGeneration(ThumbnailGenerationEvent $event) { | ||||
| 		if($this->supported_ext($event->type)) { | ||||
| 			if (method_exists($this, 'create_thumb_force') && $event->force == true) { | ||||
| @ -213,6 +244,9 @@ abstract class DataHandlerExtension extends Extension { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param DisplayingImageEvent $event | ||||
| 	 */ | ||||
| 	public function onDisplayingImage(DisplayingImageEvent $event) { | ||||
| 		global $page; | ||||
| 		if($this->supported_ext($event->image->ext)) { | ||||
| @ -229,9 +263,29 @@ abstract class DataHandlerExtension extends Extension { | ||||
| 	protected function setup() {} | ||||
| 	*/ | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $ext | ||||
| 	 * @return bool | ||||
| 	 */ | ||||
| 	abstract protected function supported_ext($ext); | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param $tmpname | ||||
| 	 * @return bool | ||||
| 	 */ | ||||
| 	abstract protected function check_contents($tmpname); | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $filename | ||||
| 	 * @param array $metadata | ||||
| 	 * @return Image|null | ||||
| 	 */ | ||||
| 	abstract protected function create_image_from_data($filename, $metadata); | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $hash | ||||
| 	 * @return bool | ||||
| 	 */ | ||||
| 	abstract protected function create_thumb($hash); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -31,15 +31,38 @@ $order_sql = null; // this feels ugly | ||||
| require_once "lib/flexihash.php"; | ||||
| 
 | ||||
| /** | ||||
|  * An object representing an entry in the images table. As of 2.2, this no | ||||
|  * longer necessarily represents an image per se, but could be a video, | ||||
|  * sound file, or any other supported upload type. | ||||
|  * Class Image | ||||
|  * | ||||
|  * An object representing an entry in the images table. | ||||
|  * | ||||
|  * As of 2.2, this no longer necessarily represents an | ||||
|  * image per se, but could be a video, sound file, or any | ||||
|  * other supported upload type. | ||||
|  */ | ||||
| class Image { | ||||
| 	/** @var null|int */ | ||||
| 	public $id = null; | ||||
| 	public $height, $width; | ||||
| 	public $hash, $filesize; | ||||
| 	public $filename, $ext; | ||||
| 
 | ||||
| 	/** @var int */ | ||||
| 	public $height; | ||||
| 
 | ||||
| 	/** @var int */ | ||||
| 	public $width; | ||||
| 
 | ||||
| 	/** @var string */ | ||||
| 	public $hash; | ||||
| 
 | ||||
| 	public $filesize; | ||||
| 
 | ||||
| 	/** @var string */ | ||||
| 	public $filename; | ||||
| 
 | ||||
| 	/** @var string */ | ||||
| 	public $ext; | ||||
| 
 | ||||
| 	/** @var string[]|null */ | ||||
| 	public $tag_array; | ||||
| 
 | ||||
| 	public $owner_id, $owner_ip; | ||||
| 	public $posted, $posted_timestamp; | ||||
| 	public $source; | ||||
| @ -47,7 +70,9 @@ class Image { | ||||
| 
 | ||||
| 	/** | ||||
| 	 * One will very rarely construct an image directly, more common | ||||
| 	 * would be to use Image::by_id, Image::by_hash, etc | ||||
| 	 * would be to use Image::by_id, Image::by_hash, etc. | ||||
| 	 * | ||||
| 	 * @param null|mixed $row | ||||
| 	 */ | ||||
| 	public function __construct($row=null) { | ||||
| 		if(!is_null($row)) { | ||||
| @ -66,7 +91,7 @@ class Image { | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Find an image by ID | ||||
| 	 * Find an image by ID. | ||||
| 	 * | ||||
| 	 * @param int $id | ||||
| 	 * @return Image | ||||
| @ -79,7 +104,7 @@ class Image { | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Find an image by hash | ||||
| 	 * Find an image by hash. | ||||
| 	 * | ||||
| 	 * @param string $hash | ||||
| 	 * @return Image | ||||
| @ -92,9 +117,9 @@ class Image { | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Pick a random image out of a set | ||||
| 	 * Pick a random image out of a set. | ||||
| 	 * | ||||
| 	 * @param array $tags | ||||
| 	 * @param string[] $tags | ||||
| 	 * @return Image | ||||
| 	 */ | ||||
| 	public static function by_random($tags=array()) { | ||||
| @ -112,9 +137,9 @@ class Image { | ||||
| 	 * | ||||
| 	 * @param int $start | ||||
| 	 * @param int $limit | ||||
| 	 * @param array $tags | ||||
| 	 * @param string[] $tags | ||||
| 	 * @throws SCoreException | ||||
| 	 * @return Array | ||||
| 	 * @return Image[] | ||||
| 	 */ | ||||
| 	public static function find_images(/*int*/ $start, /*int*/ $limit, $tags=array()) { | ||||
| 		assert(is_numeric($start)); | ||||
| @ -153,7 +178,7 @@ class Image { | ||||
| 	/** | ||||
| 	 * Count the number of image results for a given search | ||||
| 	 * | ||||
| 	 * @param array $tags | ||||
| 	 * @param string[] $tags | ||||
| 	 * @return mixed | ||||
| 	 */ | ||||
| 	public static function count_images($tags=array()) { | ||||
| @ -185,7 +210,7 @@ class Image { | ||||
| 	/** | ||||
| 	 * Count the number of pages for a given search | ||||
| 	 * | ||||
| 	 * @param array $tags | ||||
| 	 * @param string[] $tags | ||||
| 	 * @return float | ||||
| 	 */ | ||||
| 	public static function count_pages($tags=array()) { | ||||
| @ -205,7 +230,7 @@ class Image { | ||||
| 	 * Rather than simply $this_id + 1, one must take into account | ||||
| 	 * deleted images and search queries | ||||
| 	 * | ||||
| 	 * @param array $tags | ||||
| 	 * @param string[] $tags | ||||
| 	 * @param bool $next | ||||
| 	 * @return Image | ||||
| 	 */ | ||||
| @ -239,7 +264,7 @@ class Image { | ||||
| 	/** | ||||
| 	 * The reverse of get_next | ||||
| 	 * | ||||
| 	 * @param array $tags | ||||
| 	 * @param string[] $tags | ||||
| 	 * @return Image | ||||
| 	 */ | ||||
| 	public function get_prev($tags=array()) { | ||||
| @ -269,7 +294,9 @@ class Image { | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Get this image's tags as an array | ||||
| 	 * Get this image's tags as an array. | ||||
| 	 * | ||||
| 	 * @return string[] | ||||
| 	 */ | ||||
| 	public function get_tag_array() { | ||||
| 		global $database; | ||||
| @ -349,7 +376,7 @@ class Image { | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Get the tooltip for this image, formatted according to the | ||||
| 	 * configured template | ||||
| 	 * configured template. | ||||
| 	 * | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| @ -378,7 +405,7 @@ class Image { | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Figure out where the full size image is on disk | ||||
| 	 * Figure out where the full size image is on disk. | ||||
| 	 * | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| @ -387,7 +414,7 @@ class Image { | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Figure out where the thumbnail is on disk | ||||
| 	 * Figure out where the thumbnail is on disk. | ||||
| 	 * | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| @ -396,7 +423,7 @@ class Image { | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Get the original filename | ||||
| 	 * Get the original filename. | ||||
| 	 * | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| @ -405,7 +432,7 @@ class Image { | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Get the image's mime type | ||||
| 	 * Get the image's mime type. | ||||
| 	 * | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| @ -480,7 +507,9 @@ class Image { | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Set the tags for this image | ||||
| 	 * Set the tags for this image. | ||||
| 	 * | ||||
| 	 * @param string[] $tags | ||||
| 	 */ | ||||
| 	public function set_tags($tags) { | ||||
| 		global $database; | ||||
| @ -505,6 +534,11 @@ class Image { | ||||
| 					continue; | ||||
| 				} | ||||
| 
 | ||||
| 				if(mb_strlen($tag, 'UTF-8') > 255){ | ||||
| 					flash_message("The tag below is longer than 255 characters, please use a shorter tag.\n$tag\n"); | ||||
| 					continue; | ||||
| 				} | ||||
| 
 | ||||
| 				$id = $database->get_one( | ||||
| 						$database->scoreql_to_sql( | ||||
| 							"SELECT id FROM tags WHERE SCORE_STRNORM(tag) = SCORE_STRNORM(:tag)" | ||||
| @ -533,7 +567,7 @@ class Image { | ||||
| 						array("tag"=>$tag)); | ||||
| 			} | ||||
| 
 | ||||
| 			log_info("core_image", "Tags for Image #{$this->id} set to: ".implode(" ", $tags), false, array("image_id" => $this->id)); | ||||
| 			log_info("core_image", "Tags for Image #{$this->id} set to: ".implode(" ", $tags), null, array("image_id" => $this->id)); | ||||
| 			$database->cache->delete("image-{$this->id}-tags"); | ||||
| 		} | ||||
| 	} | ||||
| @ -564,7 +598,7 @@ class Image { | ||||
| 	/** | ||||
| 	 * Someone please explain this | ||||
| 	 * | ||||
| 	 * @param $tmpl | ||||
| 	 * @param string $tmpl | ||||
| 	 * @param string $_escape | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| @ -637,6 +671,10 @@ class Image { | ||||
| 		return $tmpl; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string[] $terms | ||||
| 	 * @return \Querylet | ||||
| 	 */ | ||||
| 	private static function build_search_querylet($terms) { | ||||
| 		assert(is_array($terms)); | ||||
| 		global $database; | ||||
| @ -666,6 +704,9 @@ class Image { | ||||
| 	 *   C) Runs really slow on bad databases: | ||||
| 	 *      All the subqueries are executed every time for every row in the | ||||
| 	 *      images table. Yes, MySQL does suck this much. | ||||
| 	 * | ||||
| 	 * @param string[] $terms | ||||
| 	 * @return \Querylet | ||||
| 	 */ | ||||
| 	private static function build_accurate_search_querylet($terms) { | ||||
| 		global $database; | ||||
| @ -932,16 +973,22 @@ class Image { | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		// more than one positive tag, or more than zero negative tags
 | ||||
| 		else { | ||||
| 		// more than one positive tag, and zero or more negative tags
 | ||||
| 		else if($positive_tag_count >= 1) { | ||||
| 			$tag_id_array = array(); | ||||
| 			$tags_ok = true; | ||||
| 
 | ||||
| 			$x = 0; | ||||
| 			foreach($tag_search->variables as $tag) { | ||||
| 				$tag_ids = $database->get_col("SELECT id FROM tags WHERE tag LIKE :tag", array("tag"=>$tag)); | ||||
| 				$tag_id_array = array_merge($tag_id_array, $tag_ids); | ||||
| 				$tags_ok = count($tag_ids) > 0; | ||||
| 
 | ||||
| 				$tags_ok = count($tag_ids) > 0 || !$tag_querylets[$x]->positive; | ||||
| 				if(!$tags_ok) break; | ||||
| 
 | ||||
| 				$x++; | ||||
| 			} | ||||
| 
 | ||||
| 			if($tags_ok) { | ||||
| 				$tag_id_list = join(', ', $tag_id_array); | ||||
| 
 | ||||
| @ -977,15 +1024,27 @@ class Image { | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		//zero positive tags and one or more negative tags
 | ||||
| 		//TODO: This isn't currently implemented. SEE: https://github.com/shish/shimmie2/issues/66
 | ||||
| 		else{ | ||||
| 			$query = new Querylet(" | ||||
| 				SELECT images.* | ||||
| 				FROM images | ||||
| 				WHERE 1=0 | ||||
| 			");
 | ||||
| 		} | ||||
| 		$tag_n = 0; | ||||
| 		return $query; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Class Tag | ||||
|  * | ||||
|  * A class for organising the tag related functions. | ||||
|  * | ||||
|  * All the methods are static, one should never actually use a tag object. | ||||
|  * | ||||
|  */ | ||||
| class Tag { | ||||
| 	/** | ||||
| @ -1003,7 +1062,11 @@ class Tag { | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Turn any string or array into a valid tag array | ||||
| 	 * Turn any string or array into a valid tag array. | ||||
| 	 * | ||||
| 	 * @param string|string[] $tags | ||||
| 	 * @param bool $tagme | ||||
| 	 * @return array | ||||
| 	 */ | ||||
| 	public static function explode($tags, $tagme=true) { | ||||
| 		assert(is_string($tags) || is_array($tags)); | ||||
| @ -1033,7 +1096,7 @@ class Tag { | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param $tags | ||||
| 	 * @param string|string[] $tags | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	public static function implode($tags) { | ||||
| @ -1073,6 +1136,10 @@ class Tag { | ||||
| 		return $negative ? "-$newtag" : $newtag; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $tag | ||||
| 	 * @return array | ||||
| 	 */ | ||||
| 	public static function resolve_wildcard($tag) { | ||||
| 		// if there is no wildcard, return the tag
 | ||||
| 		if(strpos($tag, "*") === false) { | ||||
| @ -1102,8 +1169,8 @@ class Tag { | ||||
| 	/** | ||||
| 	 * This function takes a list (array) of tags and changes any tags that have aliases | ||||
| 	 * | ||||
| 	 * @param array $tags Array of tags | ||||
| 	 * @return array of tags | ||||
| 	 * @param string[] $tags Array of tags | ||||
| 	 * @return array | ||||
| 	 */ | ||||
| 	public static function resolve_aliases($tags) { | ||||
| 		assert(is_array($tags)); | ||||
| @ -1139,7 +1206,11 @@ class Tag { | ||||
| 
 | ||||
| /** | ||||
|  * Move a file from PHP's temporary area into shimmie's image storage | ||||
|  * hierarchy, or throw an exception trying | ||||
|  * hierarchy, or throw an exception trying. | ||||
|  * | ||||
|  * @param DataUploadEvent $event | ||||
|  * @return bool | ||||
|  * @throws UploadException | ||||
|  */ | ||||
| function move_upload_to_archive(DataUploadEvent $event) { | ||||
| 	$target = warehouse_path("images", $event->hash); | ||||
|  | ||||
| @ -28,28 +28,32 @@ | ||||
| 
 | ||||
| 
 | ||||
| /** | ||||
|  * Class Page | ||||
|  * | ||||
|  * A data structure for holding all the bits of data that make up a page. | ||||
|  * | ||||
|  * The various extensions all add whatever they want to this structure, | ||||
|  * then Layout turns it into HTML | ||||
|  * then Layout turns it into HTML. | ||||
|  */ | ||||
| class Page { | ||||
| 	/** @name Overall */ | ||||
| 	//@{
 | ||||
| 	/** @private */ | ||||
| 	var $mode = "page"; | ||||
| 	/** @private */ | ||||
| 	var $type = "text/html; charset=utf-8"; | ||||
| 	/** @var string */ | ||||
| 	public $mode = "page"; | ||||
| 	/** @var string */ | ||||
| 	public $type = "text/html; charset=utf-8"; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Set what this page should do; "page", "data", or "redirect". | ||||
| 	 * @param string $mode | ||||
| 	 */ | ||||
| 	public function set_mode($mode) { | ||||
| 		$this->mode = $mode; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Set the page's MIME type | ||||
| 	 * Set the page's MIME type. | ||||
| 	 * @param string $type | ||||
| 	 */ | ||||
| 	public function set_type($type) { | ||||
| 		$this->type = $type; | ||||
| @ -61,20 +65,23 @@ class Page { | ||||
| 	/** @name "data" mode */ | ||||
| 	//@{
 | ||||
| 
 | ||||
| 	/** @private */ | ||||
| 	var $data = ""; | ||||
| 	/** @private */ | ||||
| 	var $filename = null; | ||||
| 	/** @var string */ | ||||
| 	private $data = ""; | ||||
| 
 | ||||
| 	/** @var string */ | ||||
| 	private $filename = null; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Set the raw data to be sent | ||||
| 	 * Set the raw data to be sent. | ||||
| 	 * @param string $data | ||||
| 	 */ | ||||
| 	public function set_data($data) { | ||||
| 		$this->data = $data; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Set the recommended download filename | ||||
| 	 * Set the recommended download filename. | ||||
| 	 * @param string $filename | ||||
| 	 */ | ||||
| 	public function set_filename($filename) { | ||||
| 		$this->filename = $filename; | ||||
| @ -86,12 +93,13 @@ class Page { | ||||
| 	/** @name "redirect" mode */ | ||||
| 	//@{
 | ||||
| 
 | ||||
| 	/** @private */ | ||||
| 	var $redirect = ""; | ||||
| 	/** @var string */ | ||||
| 	private $redirect = ""; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Set the URL to redirect to (remember to use make_link() if linking | ||||
| 	 * to a page in the same site) | ||||
| 	 * to a page in the same site). | ||||
| 	 * @param string $redirect | ||||
| 	 */ | ||||
| 	public function set_redirect($redirect) { | ||||
| 		$this->redirect = $redirect; | ||||
| @ -103,39 +111,56 @@ class Page { | ||||
| 	/** @name "page" mode */ | ||||
| 	//@{
 | ||||
| 
 | ||||
| 	/** @privatesection */ | ||||
| 	var $title = ""; | ||||
| 	var $heading = ""; | ||||
| 	var $subheading = ""; | ||||
| 	var $quicknav = ""; | ||||
| 	var $html_headers = array(); | ||||
| 	var $http_headers = array(); | ||||
| 	var $blocks = array(); | ||||
| 	/** @publicsection */ | ||||
| 	/** @var string */ | ||||
| 	public $title = ""; | ||||
| 
 | ||||
| 	/** @var string */ | ||||
| 	public $heading = ""; | ||||
| 
 | ||||
| 	/** @var string */ | ||||
| 	public $subheading = ""; | ||||
| 
 | ||||
| 	/** @var string */ | ||||
| 	public $quicknav = ""; | ||||
| 
 | ||||
| 	/** @var string[] */ | ||||
| 	public $html_headers = array(); | ||||
| 
 | ||||
| 	/** @var string[] */ | ||||
| 	public $http_headers = array(); | ||||
| 
 | ||||
| 	/** @var Block[] */ | ||||
| 	public $blocks = array(); | ||||
| 
 | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Set the window title | ||||
| 	 * Set the window title. | ||||
| 	 * @param string $title | ||||
| 	 */ | ||||
| 	public function set_title($title) { | ||||
| 		$this->title = $title; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Set the main heading | ||||
| 	 * Set the main heading. | ||||
| 	 * @param string $heading | ||||
| 	 */ | ||||
| 	public function set_heading($heading) { | ||||
| 		$this->heading = $heading; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Set the sub heading | ||||
| 	 * Set the sub heading. | ||||
| 	 * @param string $subheading | ||||
| 	 */ | ||||
| 	public function set_subheading($subheading) { | ||||
| 		$this->subheading = $subheading; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Add a line to the HTML head section | ||||
| 	 * Add a line to the HTML head section. | ||||
| 	 * @param string $line | ||||
| 	 * @param int $position | ||||
| 	 */ | ||||
| 	public function add_html_header($line, $position=50) { | ||||
| 		while(isset($this->html_headers[$position])) $position++; | ||||
| @ -144,6 +169,8 @@ class Page { | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Add a http header to be sent to the client. | ||||
| 	 * @param string $line | ||||
| 	 * @param int $position | ||||
| 	 */ | ||||
| 	public function add_http_header($line, $position=50) { | ||||
| 		while(isset($this->http_headers[$position])) $position++; | ||||
| @ -152,6 +179,7 @@ class Page { | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Get all the HTML headers that are currently set and return as a string. | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	public function get_all_html_headers() { | ||||
| 		$data = ''; | ||||
| @ -162,14 +190,15 @@ class Page { | ||||
| 	} | ||||
| 	 | ||||
| 	/** | ||||
| 	 * Removes all currently set HTML headers. (Be careful..) | ||||
| 	 * Removes all currently set HTML headers (Be careful..). | ||||
| 	 */ | ||||
| 	public function delete_all_html_headers() { | ||||
| 		$this->html_headers = array(); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Add a Block of data | ||||
| 	 * Add a Block of data to the page. | ||||
| 	 * @param Block $block | ||||
| 	 */ | ||||
| 	public function add_block(Block $block) { | ||||
| 		$this->blocks[] = $block; | ||||
| @ -180,7 +209,7 @@ class Page { | ||||
| 	// ==============================================
 | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Display the page according to the mode and data given | ||||
| 	 * Display the page according to the mode and data given. | ||||
| 	 */ | ||||
| 	public function display() { | ||||
| 		global $page, $user; | ||||
| @ -263,7 +292,7 @@ class Page { | ||||
| 			$css_files[] = $css; | ||||
| 			$css_latest = max($css_latest, filemtime($css)); | ||||
| 		} | ||||
| 		$css_cache_file = data_path("cache/style.$css_latest.css"); | ||||
| 		$css_cache_file = data_path("cache/style.$theme_name.$css_latest.css"); | ||||
| 		if(!file_exists($css_cache_file)) { | ||||
| 			$css_data = ""; | ||||
| 			foreach($css_files as $file) { | ||||
| @ -283,7 +312,7 @@ class Page { | ||||
| 			$js_files[] = $js; | ||||
| 			$js_latest = max($js_latest, filemtime($js)); | ||||
| 		} | ||||
| 		$js_cache_file = data_path("cache/script.$js_latest.js"); | ||||
| 		$js_cache_file = data_path("cache/script.$theme_name.$js_latest.js"); | ||||
| 		if(!file_exists($js_cache_file)) { | ||||
| 			$js_data = ""; | ||||
| 			foreach($js_files as $file) { | ||||
|  | ||||
| @ -1,4 +1,6 @@ | ||||
| <?php | ||||
| require_once "lib/password.php"; | ||||
| 
 | ||||
| /** @private */ | ||||
| function _new_user($row) { | ||||
| 	return new User($row); | ||||
| @ -6,9 +8,11 @@ function _new_user($row) { | ||||
| 
 | ||||
| 
 | ||||
| /** | ||||
|  * Class User | ||||
|  * | ||||
|  * An object representing a row in the "users" table. | ||||
|  * | ||||
|  * The currently logged in user will always be accessible via the global variable $user | ||||
|  * The currently logged in user will always be accessible via the global variable $user. | ||||
|  */ | ||||
| class User { | ||||
| 	/** @var int */ | ||||
| @ -22,10 +26,11 @@ class User { | ||||
| 
 | ||||
| 	public $join_date; | ||||
| 
 | ||||
| 	/** @var string */ | ||||
| 	public $passhash; | ||||
| 
 | ||||
| 	/** @var UserClass */ | ||||
| 	var $class; | ||||
| 	public $class; | ||||
| 
 | ||||
| 	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||||
| 	* Initialisation                                               * | ||||
| @ -38,7 +43,9 @@ class User { | ||||
| 
 | ||||
| 	/** | ||||
| 	 * One will very rarely construct a user directly, more common | ||||
| 	 * would be to use User::by_id, User::by_session, etc | ||||
| 	 * would be to use User::by_id, User::by_session, etc. | ||||
| 	 * | ||||
| 	 * @param mixed $row | ||||
| 	 */ | ||||
| 	public function __construct($row) { | ||||
| 		global $_user_classes; | ||||
| @ -60,7 +67,7 @@ class User { | ||||
| 	 */ | ||||
| 	public static function by_session(/*string*/ $name, /*string*/ $session) { | ||||
| 		global $config, $database; | ||||
| 		$row = $database->cache->get("user-session-$name-$session"); | ||||
| 		$row = $database->cache->get("user-session:$name-$session"); | ||||
| 		if(!$row) { | ||||
| 			if($database->get_driver_name() === "mysql") { | ||||
| 				$query = "SELECT * FROM users WHERE name = :name AND md5(concat(pass, :ip)) = :sess"; | ||||
| @ -69,7 +76,7 @@ class User { | ||||
| 				$query = "SELECT * FROM users WHERE name = :name AND md5(pass || :ip) = :sess"; | ||||
| 			} | ||||
| 			$row = $database->get_row($query, array("name"=>$name, "ip"=>get_session_ip($config), "sess"=>$session)); | ||||
| 			$database->cache->set("user-session-$name-$session", $row, 600); | ||||
| 			$database->cache->set("user-session:$name-$session", $row, 600); | ||||
| 		} | ||||
| 		return is_null($row) ? null : new User($row); | ||||
| 	} | ||||
| @ -104,18 +111,23 @@ class User { | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Construct a User by name and hash. | ||||
| 	 * Construct a User by name and password. | ||||
| 	 * @param string $name | ||||
| 	 * @param string $hash | ||||
| 	 * @param string $pass | ||||
| 	 * @return null|User | ||||
| 	 */ | ||||
| 	public static function by_name_and_hash(/*string*/ $name, /*string*/ $hash) { | ||||
| 	public static function by_name_and_pass(/*string*/ $name, /*string*/ $pass) { | ||||
| 		assert(is_string($name)); | ||||
| 		assert(is_string($hash)); | ||||
| 		assert(strlen($hash) == 32); | ||||
| 		global $database; | ||||
| 		$row = $database->get_row($database->scoreql_to_sql("SELECT * FROM users WHERE SCORE_STRNORM(name) = SCORE_STRNORM(:name) AND pass = :hash"), array("name"=>$name, "hash"=>$hash)); | ||||
| 		return is_null($row) ? null : new User($row); | ||||
| 		assert(is_string($pass)); | ||||
| 		$user = User::by_name($name); | ||||
| 		if($user) { | ||||
| 			if($user->passhash == md5(strtolower($name) . $pass)) { | ||||
| 				$user->set_password($pass); | ||||
| 			} | ||||
| 			if(password_verify($pass, $user->passhash)) { | ||||
| 				return $user; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| @ -145,7 +157,7 @@ class User { | ||||
| 
 | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Test if this user is anonymous (not logged in) | ||||
| 	 * Test if this user is anonymous (not logged in). | ||||
| 	 * | ||||
| 	 * @return bool | ||||
| 	 */ | ||||
| @ -155,7 +167,7 @@ class User { | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Test if this user is logged in | ||||
| 	 * Test if this user is logged in. | ||||
| 	 * | ||||
| 	 * @return bool | ||||
| 	 */ | ||||
| @ -165,7 +177,7 @@ class User { | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Test if this user is an administrator | ||||
| 	 * Test if this user is an administrator. | ||||
| 	 * | ||||
| 	 * @return bool | ||||
| 	 */ | ||||
| @ -188,11 +200,14 @@ class User { | ||||
| 	 */ | ||||
| 	public function set_password(/*string*/ $password) { | ||||
| 		global $database; | ||||
| 		$hash = md5(strtolower($this->name) . $password); | ||||
| 		$database->Execute("UPDATE users SET pass=:hash WHERE id=:id", array("hash"=>$hash, "id"=>$this->id)); | ||||
| 		$this->passhash = password_hash($password, PASSWORD_BCRYPT); | ||||
| 		$database->Execute("UPDATE users SET pass=:hash WHERE id=:id", array("hash"=>$this->passhash, "id"=>$this->id)); | ||||
| 		log_info("core-user", 'Set password for '.$this->name); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $address | ||||
| 	 */ | ||||
| 	public function set_email(/*string*/ $address) { | ||||
| 		global $database; | ||||
| 		$database->Execute("UPDATE users SET email=:email WHERE id=:id", array("email"=>$address, "id"=>$this->id)); | ||||
| @ -201,7 +216,8 @@ class User { | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Get a snippet of HTML which will render the user's avatar, be that | ||||
| 	 * a local file, a remote file, a gravatar, a something else, etc | ||||
| 	 * a local file, a remote file, a gravatar, a something else, etc. | ||||
| 	 * | ||||
| 	 * @return String of HTML | ||||
| 	 */ | ||||
| 	public function get_avatar_html() { | ||||
| @ -224,14 +240,14 @@ class User { | ||||
| 	 * Get an auth token to be used in POST forms | ||||
| 	 * | ||||
| 	 * password = secret, avoid storing directly | ||||
| 	 * passhash = md5(password), so someone who gets to the database can't get passwords | ||||
| 	 * passhash = bcrypt(password), so someone who gets to the database can't get passwords | ||||
| 	 * sesskey  = md5(passhash . IP), so if it gets sniffed it can't be used from another IP, | ||||
| 	 *            and it can't be used to get the passhash to generate new sesskeys | ||||
| 	 * authtok  = md5(sesskey, salt), presented to the user in web forms, to make sure that | ||||
| 	 *            the form was generated within the session. Salted and re-hashed so that | ||||
| 	 *            reading a web page from the user's cache doesn't give access to the session key | ||||
| 	 * | ||||
| 	 * @return String containing auth token (MD5sum) | ||||
| 	 * @return string A string containing auth token (MD5sum) | ||||
| 	 */ | ||||
| 	public function get_auth_token() { | ||||
| 		global $config; | ||||
|  | ||||
| @ -1,11 +1,34 @@ | ||||
| <?php | ||||
| /** | ||||
|  * @global UserClass[] $_user_classes | ||||
|  */ | ||||
| $_user_classes = array(); | ||||
| 
 | ||||
| /** | ||||
|  * Class UserClass | ||||
|  */ | ||||
| class UserClass { | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @var null|string | ||||
| 	 */ | ||||
| 	public $name = null; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @var \UserClass|null | ||||
| 	 */ | ||||
| 	public $parent = null; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @var array | ||||
| 	 */ | ||||
| 	public $abilities = array(); | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $name | ||||
| 	 * @param null|string $parent | ||||
| 	 * @param array $abilities | ||||
| 	 */ | ||||
| 	public function __construct($name, $parent=null, $abilities=array()) { | ||||
| 		global $_user_classes; | ||||
| 
 | ||||
|  | ||||
| @ -124,6 +124,12 @@ function no_escape($input) { | ||||
| 	return $input; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * @param string $name | ||||
|  * @param array $attrs | ||||
|  * @param array $children | ||||
|  * @return string | ||||
|  */ | ||||
| function xml_tag($name, $attrs=array(), $children=array()) { | ||||
| 	$xml = "<$name "; | ||||
| 	foreach($attrs as $k => $v) { | ||||
| @ -427,6 +433,10 @@ function make_form($target, $method="POST", $multipart=False, $form_id="", $onsu | ||||
| 	return '<form action="'.$target.'" method="'.$method.'" '.$extra.'>'.$auth; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * @param string $file The filename | ||||
|  * @return string | ||||
|  */ | ||||
| function mtimefile($file) { | ||||
| 	$data_href = get_base_href(); | ||||
| 	$mtime = filemtime($file); | ||||
| @ -445,8 +455,11 @@ function get_theme() { | ||||
| 	return $theme; | ||||
| } | ||||
| 
 | ||||
| /* | ||||
|  * like glob, with support for matching very long patterns with braces | ||||
| /** | ||||
|  * Like glob, with support for matching very long patterns with braces. | ||||
|  * | ||||
|  * @param string $pattern | ||||
|  * @return array | ||||
|  */ | ||||
| function zglob($pattern) { | ||||
| 	$results = array(); | ||||
| @ -470,6 +483,9 @@ function zglob($pattern) { | ||||
| * CAPTCHA abstraction                                                       * | ||||
| \* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | ||||
| 
 | ||||
| /** | ||||
|  * @return string | ||||
|  */ | ||||
| function captcha_get_html() { | ||||
| 	global $config, $user; | ||||
| 
 | ||||
| @ -492,6 +508,9 @@ function captcha_get_html() { | ||||
| 	return $captcha; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * @return bool | ||||
|  */ | ||||
| function captcha_check() { | ||||
| 	global $config, $user; | ||||
| 
 | ||||
| @ -593,7 +612,10 @@ function getMimeType($file, $ext="", $list=false) { | ||||
| 	return 'application/octet-stream'; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /** | ||||
|  * @param string $mime_type | ||||
|  * @return bool|string | ||||
|  */ | ||||
| function getExtension ($mime_type){ | ||||
| 	if(empty($mime_type)){ | ||||
| 		return false; | ||||
| @ -608,7 +630,7 @@ function getExtension ($mime_type){ | ||||
|  * @private | ||||
|  */ | ||||
| function _version_check() { | ||||
| 	$min_version = "5.3.0"; | ||||
| 	$min_version = "5.3.7"; | ||||
| 	if(version_compare(PHP_VERSION, $min_version) == -1) { | ||||
| 		print " | ||||
| Currently SCore Engine doesn't support versions of PHP lower than $min_version -- | ||||
| @ -762,6 +784,11 @@ function get_prefixed_cookie(/*string*/ $name) { | ||||
|  * The counterpart for get_prefixed_cookie, this works like php's | ||||
|  * setcookie method, but prepends the site-wide cookie prefix to | ||||
|  * the $name argument before doing anything. | ||||
|  * | ||||
|  * @param string $name | ||||
|  * @param string $value | ||||
|  * @param int $time | ||||
|  * @param string $path | ||||
|  */ | ||||
| function set_prefixed_cookie($name, $value, $time, $path) { | ||||
| 	global $config; | ||||
| @ -770,13 +797,16 @@ function set_prefixed_cookie($name, $value, $time, $path) { | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Set (or extend) a flash-message cookie | ||||
|  * Set (or extend) a flash-message cookie. | ||||
|  * | ||||
|  * This can optionally be done at the same time as saving a log message with log_*() | ||||
|  * | ||||
|  * Generally one should flash a message in onPageRequest and log a message wherever | ||||
|  * the action actually takes place (eg onWhateverElse) - but much of the time, actions | ||||
|  * are taken from within onPageRequest... | ||||
|  * | ||||
|  * @param string $text | ||||
|  * @param string $type | ||||
|  */ | ||||
| function flash_message(/*string*/ $text, /*string*/ $type="info") { | ||||
| 	$current = get_prefixed_cookie("flash_message"); | ||||
| @ -816,10 +846,9 @@ function get_base_href() { | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * A shorthand way to send a TextFormattingEvent and get the | ||||
|  * results | ||||
|  * A shorthand way to send a TextFormattingEvent and get the results. | ||||
|  * | ||||
|  * @param $string | ||||
|  * @param string $string | ||||
|  * @return string | ||||
|  */ | ||||
| function format_text(/*string*/ $string) { | ||||
| @ -828,6 +857,12 @@ function format_text(/*string*/ $string) { | ||||
| 	return $tfe->formatted; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * @param string $base | ||||
|  * @param string $hash | ||||
|  * @param bool $create | ||||
|  * @return string | ||||
|  */ | ||||
| function warehouse_path(/*string*/ $base, /*string*/ $hash, /*bool*/ $create=true) { | ||||
| 	$ab = substr($hash, 0, 2); | ||||
| 	$cd = substr($hash, 2, 2); | ||||
| @ -841,12 +876,21 @@ function warehouse_path(/*string*/ $base, /*string*/ $hash, /*bool*/ $create=tru | ||||
| 	return $pa; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * @param string $filename | ||||
|  * @return string | ||||
|  */ | ||||
| function data_path($filename) { | ||||
| 	$filename = "data/" . $filename; | ||||
| 	if(!file_exists(dirname($filename))) mkdir(dirname($filename), 0755, true); | ||||
| 	return $filename; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * @param string $url | ||||
|  * @param string $mfile | ||||
|  * @return array|bool | ||||
|  */ | ||||
| function transload($url, $mfile) { | ||||
| 	global $config; | ||||
| 
 | ||||
| @ -935,15 +979,37 @@ if (!function_exists('http_parse_headers')) { #http://www.php.net/manual/en/func | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| function findHeader ($headers, $name){ | ||||
| 	//HTTP Headers can sometimes be lowercase which will cause issues.
 | ||||
| 	//In cases like these, we need to make sure to check for them if the camelcase version does not exist.
 | ||||
| 	$header = FALSE; | ||||
| 
 | ||||
| 	if(array_key_exists($name, $headers)){ | ||||
| 		$header = $headers[$name]; | ||||
| 	}else{ | ||||
| 		$headers = array_change_key_case($headers); | ||||
| 		if(array_key_exists(strtolower($name), $headers)){ | ||||
| 			$header = $headers[strtolower($name)]; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return $header; | ||||
| } | ||||
| 
 | ||||
| $_included = array(); | ||||
| /** | ||||
|  * Get the active contents of a .php file | ||||
|  * | ||||
|  * @param string $fname | ||||
|  * @return string|null | ||||
|  */ | ||||
| function manual_include($fname) { | ||||
| 	if(!file_exists($fname)) return; | ||||
| 
 | ||||
| 	global $_included; | ||||
| 	if(in_array($fname, $_included)) return; | ||||
| 
 | ||||
| 	if(!file_exists($fname)) return null; | ||||
| 
 | ||||
| 	if(in_array($fname, $_included)) return null; | ||||
| 
 | ||||
| 	$_included[] = $fname; | ||||
| 
 | ||||
| 	print "$fname\n"; | ||||
| @ -990,6 +1056,12 @@ define("SCORE_LOG_NOTSET", 0); | ||||
|  * $flash = null (default) - log to server only, no flash message | ||||
|  * $flash = true           - show the message to the user as well | ||||
|  * $flash = "some string"  - log the message, flash the string | ||||
|  * | ||||
|  * @param string $section | ||||
|  * @param int $priority | ||||
|  * @param string $message | ||||
|  * @param null|bool|string $flash | ||||
|  * @param array $args | ||||
|  */ | ||||
| function log_msg(/*string*/ $section, /*int*/ $priority, /*string*/ $message, $flash=null, $args=array()) { | ||||
| 	send_event(new LogEvent($section, $priority, $message, $args)); | ||||
| @ -1012,10 +1084,13 @@ function log_warning( /*string*/ $section, /*string*/ $message, $flash=null, $ar | ||||
| function log_error(   /*string*/ $section, /*string*/ $message, $flash=null, $args=array()) {log_msg($section, SCORE_LOG_ERROR, $message, $flash, $args);} | ||||
| function log_critical(/*string*/ $section, /*string*/ $message, $flash=null, $args=array()) {log_msg($section, SCORE_LOG_CRITICAL, $message, $flash, $args);} | ||||
| 
 | ||||
| /** | ||||
|  * Get a unique ID for this request, useful for grouping log messages | ||||
|  */ | ||||
| 
 | ||||
| $_request_id = null; | ||||
| /** | ||||
|  * Get a unique ID for this request, useful for grouping log messages. | ||||
|  * | ||||
|  * @return null|string | ||||
|  */ | ||||
| function get_request_id() { | ||||
| 	global $_request_id; | ||||
| 	if(!$_request_id) { | ||||
| @ -1197,7 +1272,11 @@ function full_copy($source, $target) { | ||||
| $_event_listeners = array(); | ||||
| 
 | ||||
| /** | ||||
|  * Register an Extension | ||||
|  * Register an Extension. | ||||
|  * | ||||
|  * @param Extension $extension | ||||
|  * @param int $pos | ||||
|  * @param array $events | ||||
|  */ | ||||
| function add_event_listener(Extension $extension, $pos=50, $events=array()) { | ||||
| 	global $_event_listeners; | ||||
| @ -1214,7 +1293,9 @@ function add_event_listener(Extension $extension, $pos=50, $events=array()) { | ||||
| $_event_count = 0; | ||||
| 
 | ||||
| /** | ||||
|  * Send an event to all registered Extensions | ||||
|  * Send an event to all registered Extensions. | ||||
|  * | ||||
|  * @param Event $event | ||||
|  */ | ||||
| function send_event(Event $event) { | ||||
| 	global $_event_listeners, $_event_count; | ||||
| @ -1227,7 +1308,9 @@ function send_event(Event $event) { | ||||
| 	ksort($my_event_listeners); | ||||
| 	foreach($my_event_listeners as $listener) { | ||||
| 		ctx_log_start(get_class($listener)); | ||||
| 		if(method_exists($listener, $method_name)) { | ||||
| 			$listener->$method_name($event); | ||||
| 		} | ||||
| 		ctx_log_endok(); | ||||
| 	} | ||||
| 	$_event_count++; | ||||
| @ -1248,7 +1331,7 @@ $_load_start = microtime(true); | ||||
|  * Collects some debug information (execution time, memory usage, queries, etc) | ||||
|  * and formats it to stick in the footer of the page. | ||||
|  * | ||||
|  * @return String of debug info to add to the page. | ||||
|  * @return string debug info to add to the page. | ||||
|  */ | ||||
| function get_debug_info() { | ||||
| 	global $config, $_event_count, $database, $_execs, $_load_start; | ||||
| @ -1261,12 +1344,13 @@ function get_debug_info() { | ||||
| 	else { | ||||
| 		$commit = " (".$config->get_string("commit_hash").")"; | ||||
| 	} | ||||
| 	$time = sprintf("%5.2f", microtime(true) - $_load_start); | ||||
| 	$time = sprintf("%.2f", microtime(true) - $_load_start); | ||||
| 	$dbtime = sprintf("%.2f", $database->dbtime); | ||||
| 	$i_files = count(get_included_files()); | ||||
| 	$hits = $database->cache->get_hits(); | ||||
| 	$miss = $database->cache->get_misses(); | ||||
| 
 | ||||
| 	$debug = "<br>Took $time seconds and {$i_mem}MB of RAM"; | ||||
| 	$debug = "<br>Took $time seconds (db:$dbtime) and {$i_mem}MB of RAM"; | ||||
| 	$debug .= "; Used $i_files files and $_execs queries"; | ||||
| 	$debug .= "; Sent $_event_count events"; | ||||
| 	$debug .= "; $hits cache hits and $miss misses"; | ||||
| @ -1282,6 +1366,10 @@ function get_debug_info() { | ||||
| 
 | ||||
| /** @privatesection */ | ||||
| 
 | ||||
| /** | ||||
|  * @param array|string $arr | ||||
|  * @return array|string | ||||
|  */ | ||||
| function _stripslashes_r($arr) { | ||||
| 	return is_array($arr) ? array_map('_stripslashes_r', $arr) : stripslashes($arr); | ||||
| } | ||||
| @ -1325,6 +1413,10 @@ function _sanitise_environment() { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * @param string $_theme | ||||
|  * @return array | ||||
|  */ | ||||
| function _get_themelet_files($_theme) { | ||||
| 	$base_themelets = array(); | ||||
| 	if(file_exists('themes/'.$_theme.'/custompage.class.php')) $base_themelets[] = 'themes/'.$_theme.'/custompage.class.php'; | ||||
| @ -1407,6 +1499,7 @@ function _load_extensions() { | ||||
| 
 | ||||
| /** | ||||
|  * Used to display fatal errors to the web user. | ||||
|  * @param Exception $e | ||||
|  */ | ||||
| function _fatal_error(Exception $e) { | ||||
| 	$version = VERSION; | ||||
| @ -1438,6 +1531,9 @@ function _fatal_error(Exception $e) { | ||||
|  * | ||||
|  * Necessary because various servers and various clients | ||||
|  * think that / is special... | ||||
|  * | ||||
|  * @param string $str | ||||
|  * @return string | ||||
|  */ | ||||
| function _decaret($str) { | ||||
| 	$out = ""; | ||||
| @ -1456,6 +1552,9 @@ function _decaret($str) { | ||||
| 	return $out; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * @return User | ||||
|  */ | ||||
| function _get_user() { | ||||
| 	global $config; | ||||
| 	$user = null; | ||||
|  | ||||
| @ -17,22 +17,33 @@ | ||||
|  *  <br>Download the contents of the database in plain text format, useful | ||||
|  *  for backups. | ||||
|  *  <p>Image dump: | ||||
|  *  <br>Download all the images as a .zip file | ||||
|  *  <br>Download all the images as a .zip file (Requires ZipArchive) | ||||
|  */ | ||||
| 
 | ||||
| /** | ||||
|  * Sent when the admin page is ready to be added to | ||||
|  */ | ||||
| class AdminBuildingEvent extends Event { | ||||
| 	var $page; | ||||
| 	/** @var \Page */ | ||||
| 	public $page; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param Page $page | ||||
| 	 */ | ||||
| 	public function __construct(Page $page) { | ||||
| 		$this->page = $page; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| class AdminActionEvent extends Event { | ||||
| 	var $action; | ||||
| 	var $redirect = true; | ||||
| 	/** @var string */ | ||||
| 	public $action; | ||||
| 	/** @var bool */ | ||||
| 	public $redirect = true; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $action | ||||
| 	 */ | ||||
| 	public function __construct(/*string*/ $action) { | ||||
| 		$this->action = $action; | ||||
| 	} | ||||
|  | ||||
| @ -12,6 +12,12 @@ class AdminPageTheme extends Themelet { | ||||
| 		$page->add_block(new NavBlock()); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $name | ||||
| 	 * @param string $action | ||||
| 	 * @param bool $protected | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	protected function button(/*string*/ $name, /*string*/ $action, /*boolean*/ $protected=false) { | ||||
| 		$c_protected = $protected ? " protected" : ""; | ||||
| 		$html = make_form(make_link("admin/$action"), "POST", false, null, null, "admin$c_protected"); | ||||
| @ -39,6 +45,7 @@ class AdminPageTheme extends Themelet { | ||||
| 		$html = ""; | ||||
| 		$html .= $this->button("All tags to lowercase", "lowercase_all_tags", true); | ||||
| 		$html .= $this->button("Recount tag use", "recount_tag_use", false); | ||||
| 		if(class_exists('ZipArchive')) | ||||
| 			$html .= $this->button("Download all images", "download_all_images", false); | ||||
|         $html .= $this->button("Download database contents", "database_dump", false); | ||||
| 		if($database->get_driver_name() == "mysql") | ||||
|  | ||||
| @ -11,9 +11,15 @@ | ||||
|  */ | ||||
| 
 | ||||
| class AddAliasEvent extends Event { | ||||
| 	var $oldtag; | ||||
| 	var $newtag; | ||||
| 	/** @var string  */ | ||||
| 	public $oldtag; | ||||
| 	/** @var string  */ | ||||
| 	public $newtag; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $oldtag | ||||
| 	 * @param string $newtag | ||||
| 	 */ | ||||
| 	public function __construct($oldtag, $newtag) { | ||||
| 		$this->oldtag = trim($oldtag); | ||||
| 		$this->newtag = trim($newtag); | ||||
| @ -124,6 +130,10 @@ class AliasEditor extends Extension { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param Database $database | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	private function get_alias_csv(Database $database) { | ||||
| 		$csv = ""; | ||||
| 		$aliases = $database->get_pairs("SELECT oldtag, newtag FROM aliases ORDER BY newtag"); | ||||
| @ -133,6 +143,10 @@ class AliasEditor extends Extension { | ||||
| 		return $csv; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param Database $database | ||||
| 	 * @param string $csv | ||||
| 	 */ | ||||
| 	private function add_alias_csv(Database $database, /*string*/ $csv) { | ||||
| 		$csv = str_replace("\r", "\n", $csv); | ||||
| 		foreach(explode("\n", $csv) as $line) { | ||||
| @ -148,9 +162,15 @@ class AliasEditor extends Extension { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// add alias *after* mass tag editing, else the MTE will
 | ||||
| 	// search for the images and be redirected to the alias,
 | ||||
| 	// missing out the images tagged with the oldtag
 | ||||
| 	/** | ||||
| 	 * Get the priority for this extension. | ||||
| 	 * | ||||
| 	 * Add alias *after* mass tag editing, else the MTE will | ||||
| 	 * search for the images and be redirected to the alias, | ||||
| 	 * missing out the images tagged with the old tag. | ||||
| 	 * | ||||
| 	 * @return int | ||||
| 	 */ | ||||
| 	public function get_priority() {return 60;} | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -1,11 +1,14 @@ | ||||
| <?php | ||||
| 
 | ||||
| class AliasEditorTheme extends Themelet { | ||||
| 	/* | ||||
| 	 * Show a page of aliases: | ||||
| 	/** | ||||
| 	 * Show a page of aliases. | ||||
| 	 * | ||||
| 	 * $aliases = an array of ($old_tag => $new_tag) | ||||
| 	 * $can_manage = whether things like "add new alias" should be shown | ||||
| 	 * Note: $can_manage = whether things like "add new alias" should be shown | ||||
| 	 * | ||||
| 	 * @param array $aliases An array of ($old_tag => $new_tag) | ||||
| 	 * @param int $pageNumber | ||||
| 	 * @param int $totalPages | ||||
| 	 */ | ||||
| 	public function display_aliases($aliases, $pageNumber, $totalPages) { | ||||
| 		global $page, $user; | ||||
|  | ||||
| @ -9,14 +9,22 @@ | ||||
|  *  Simply enable this extention in the extention manager to enable arrow key navigation. | ||||
|  */ | ||||
| class ArrowkeyNavigation extends Extension { | ||||
| 	# Adds functionality for post/view on images
 | ||||
| 	/** | ||||
| 	 * Adds functionality for post/view on images. | ||||
| 	 * | ||||
| 	 * @param DisplayingImageEvent $event | ||||
| 	 */ | ||||
| 	public function onDisplayingImage(DisplayingImageEvent $event) { | ||||
| 		$prev_url = make_http(make_link("post/prev/".$event->image->id)); | ||||
| 		$next_url = make_http(make_link("post/next/".$event->image->id)); | ||||
| 		$this->add_arrowkeys_code($prev_url, $next_url); | ||||
| 	} | ||||
| 
 | ||||
| 	# Adds functionality for post/list
 | ||||
| 	/** | ||||
| 	 * Adds functionality for post/list. | ||||
| 	 * | ||||
| 	 * @param PageRequestEvent $event | ||||
| 	 */ | ||||
| 	public function onPageRequest(PageRequestEvent $event) { | ||||
| 		if($event->page_matches("post/list")) { | ||||
| 			$pageinfo = $this->get_list_pageinfo($event); | ||||
| @ -26,7 +34,12 @@ class ArrowkeyNavigation extends Extension { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	# adds the javascript to the page with the given urls
 | ||||
| 	/** | ||||
| 	 * Adds the javascript to the page with the given urls. | ||||
| 	 * | ||||
| 	 * @param string $prev_url | ||||
| 	 * @param string $next_url | ||||
| 	 */ | ||||
| 	private function add_arrowkeys_code($prev_url, $next_url) { | ||||
| 		global $page; | ||||
| 
 | ||||
| @ -41,8 +54,13 @@ class ArrowkeyNavigation extends Extension { | ||||
| 			</script>", 60);
 | ||||
| 	} | ||||
| 
 | ||||
| 	# returns info about the current page number
 | ||||
| 	private function get_list_pageinfo($event) { | ||||
| 	/** | ||||
| 	 * Returns info about the current page number. | ||||
| 	 * | ||||
| 	 * @param PageRequestEvent $event | ||||
| 	 * @return array | ||||
| 	 */ | ||||
| 	private function get_list_pageinfo(PageRequestEvent $event) { | ||||
| 		global $config, $database; | ||||
| 
 | ||||
| 		// get the amount of images per page
 | ||||
|  | ||||
| @ -9,8 +9,18 @@ | ||||
|  * | ||||
|  */ | ||||
| class AuthorSetEvent extends Event { | ||||
|     var $image, $user, $author; | ||||
| 	/** @var \Image  */ | ||||
| 	public $image; | ||||
| 	/** @var \User  */ | ||||
| 	public $user; | ||||
| 	/** @var string */ | ||||
| 	public $author; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param Image $image | ||||
| 	 * @param User $user | ||||
| 	 * @param string $author | ||||
| 	 */ | ||||
| 	public function __construct(Image $image, User $user, /*string*/ $author) | ||||
|     { | ||||
|         $this->image = $image; | ||||
| @ -937,8 +947,11 @@ class Artists extends Extension { | ||||
|         return $result; | ||||
|     } | ||||
| 
 | ||||
| 	/* | ||||
| 	* HERE WE GET THE ID OF THE ARTIST | ||||
| 	/** | ||||
| 	 * HERE WE GET THE ID OF THE ARTIST. | ||||
| 	 * | ||||
| 	 * @param string $name | ||||
| 	 * @return string|int | ||||
| 	 */ | ||||
| 	private function get_artist_id($name){ | ||||
| 		global $database; | ||||
| @ -1203,7 +1216,8 @@ class Artists extends Extension { | ||||
| 	/* | ||||
| 	* HERE WE GET THE INFO OF THE ALIAS | ||||
| 	*/ | ||||
| 	private function get_alias($artistID){ | ||||
| 	private function get_alias($artistID) | ||||
| 	{ | ||||
|             if (!is_numeric($artistID)) return; | ||||
| 
 | ||||
|             global $database; | ||||
|  | ||||
| @ -1,6 +1,10 @@ | ||||
| <?php | ||||
| class ArtistsTheme extends Themelet { | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $author | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	public function get_author_editor_html(/*string*/ $author) { | ||||
| 		$h_author = html_escape($author); | ||||
| 		return " | ||||
| @ -14,6 +18,11 @@ class ArtistsTheme extends Themelet { | ||||
| 		";
 | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $mode | ||||
| 	 * @param null|int $artistID | ||||
| 	 * @param bool $is_admin | ||||
| 	 */ | ||||
| 	public function sidebar_options(/*string*/ $mode, $artistID=NULL, $is_admin=FALSE){ | ||||
| 		global $page, $user; | ||||
| 
 | ||||
|  | ||||
| @ -69,24 +69,27 @@ xanax | ||||
| 		$sb = new SetupBlock("Banned Phrases"); | ||||
| 		$sb->add_label("One per line, lines that start with slashes are treated as regex<br/>"); | ||||
| 		$sb->add_longtext_option("banned_words"); | ||||
| 		$failed = array(); | ||||
| 		foreach($this->get_words() as $word) { | ||||
| 			if($word[0] == '/') { | ||||
| 				if(preg_match($word, "") === false) { | ||||
| 					$failed[] = $word; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		if($failed) { | ||||
| 			$sb->add_label("Failed regexes: ".join(", ", $failed)); | ||||
| 		} | ||||
| 		$event->panel->add_block($sb); | ||||
| 	} | ||||
| 
 | ||||
| 	private function test_text($comment, $ex) { | ||||
| 		global $config; | ||||
| 
 | ||||
| 		$banned = $config->get_string("banned_words"); | ||||
| 		$comment = strtolower($comment); | ||||
| 
 | ||||
| 		foreach(explode("\n", $banned) as $word) { | ||||
| 			$word = trim(strtolower($word)); | ||||
| 			if(strlen($word) == 0) { | ||||
| 				// line is blank
 | ||||
| 				continue; | ||||
| 			} | ||||
| 			else if($word[0] == '/') { | ||||
| 		foreach($this->get_words() as $word) { | ||||
| 			if($word[0] == '/') { | ||||
| 				// lines that start with slash are regex
 | ||||
| 				if(preg_match($word, $comment)) { | ||||
| 				if(preg_match($word, $comment) === 1) { | ||||
| 					throw $ex; | ||||
| 				} | ||||
| 			} | ||||
| @ -99,6 +102,23 @@ xanax | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	private function get_words() { | ||||
| 		global $config; | ||||
| 		$words = array(); | ||||
| 
 | ||||
| 		$banned = $config->get_string("banned_words"); | ||||
| 		foreach(explode("\n", $banned) as $word) { | ||||
| 			$word = trim(strtolower($word)); | ||||
| 			if(strlen($word) == 0) { | ||||
| 				// line is blank
 | ||||
| 				continue; | ||||
| 			} | ||||
| 			$words[] = $word; | ||||
| 		} | ||||
| 
 | ||||
| 		return $words; | ||||
| 	} | ||||
| 
 | ||||
| 	public function get_priority() {return 30;} | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -26,6 +26,10 @@ | ||||
|  */ | ||||
| 
 | ||||
| class BBCode extends FormatterExtension { | ||||
| 	/** | ||||
| 	 * @param string $text | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	public function format(/*string*/ $text) { | ||||
| 		$text = $this->extract_code($text); | ||||
| 		foreach(array( | ||||
| @ -35,6 +39,7 @@ class BBCode extends FormatterExtension { | ||||
| 		} | ||||
| 		$text = preg_replace('!^>>([^\d].+)!', '<blockquote><small>$1</small></blockquote>', $text); | ||||
| 		$text = preg_replace('!>>(\d+)(#c?\d+)?!s', '<a class="shm-clink" data-clink-sel="$2" href="'.make_link('post/view/$1$2').'">>>$1$2</a>', $text); | ||||
| 		$text = preg_replace('!\[anchor=(.*?)\](.*?)\[/anchor\]!s', '<span class="anchor">$2 <a class="alink" href="#bb-$1" name="bb-$1" title="link to this anchor"> ¶ </a></span>', $text);  // add "bb-" to avoid clashing with eg #top
 | ||||
| 		$text = preg_replace('!\[url=site://(.*?)(#c\d+)?\](.*?)\[/url\]!s', '<a class="shm-clink" data-clink-sel="$2" href="'.make_link('$1$2').'">$3</a>', $text); | ||||
| 		$text = preg_replace('!\[url\]site://(.*?)(#c\d+)?\[/url\]!s', '<a class="shm-clink" data-clink-sel="$2" href="'.make_link('$1$2').'">$1$2</a>', $text); | ||||
| 		$text = preg_replace('!\[url=((?:https?|ftp|irc|mailto)://.*?)\](.*?)\[/url\]!s', '<a href="$1">$2</a>', $text); | ||||
| @ -62,6 +67,10 @@ class BBCode extends FormatterExtension { | ||||
| 		return $text; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $text | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	public function strip(/*string*/ $text) { | ||||
| 		foreach(array( | ||||
| 			"b", "i", "u", "s", "sup", "sub", "h1", "h2", "h3", "h4", | ||||
| @ -69,6 +78,7 @@ class BBCode extends FormatterExtension { | ||||
| 		) as $el) { | ||||
| 			$text = preg_replace("!\[$el\](.*?)\[/$el\]!s", '$1', $text); | ||||
| 		} | ||||
| 		$text = preg_replace("!\[anchor=(.*?)\](.*?)\[/anchor\]!s", '$2', $text); | ||||
| 		$text = preg_replace("!\[url=(.*?)\](.*?)\[/url\]!s", '$2', $text); | ||||
| 		$text = preg_replace("!\[img\](.*?)\[/img\]!s", "", $text); | ||||
| 		$text = preg_replace("!\[\[([^\|\]]+)\|([^\]]+)\]\]!s", '$2', $text); | ||||
| @ -81,7 +91,10 @@ class BBCode extends FormatterExtension { | ||||
| 		return $text; | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $text | ||||
| 	 * @return mixed | ||||
| 	 */ | ||||
| 	private function filter_spoiler(/*string*/ $text) { | ||||
| 		return str_replace( | ||||
| 			array("[spoiler]","[/spoiler]"), | ||||
| @ -89,6 +102,10 @@ class BBCode extends FormatterExtension { | ||||
| 			$text); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $text | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	private function strip_spoiler(/*string*/ $text) { | ||||
| 		$l1 = strlen("[spoiler]"); | ||||
| 		$l2 = strlen("[/spoiler]"); | ||||
| @ -110,6 +127,10 @@ class BBCode extends FormatterExtension { | ||||
| 		return $text; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $text | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	private function extract_code(/*string*/ $text) { | ||||
| 		# at the end of this function, the only code! blocks should be
 | ||||
| 		# the ones we've added -- others may contain malicious content,
 | ||||
| @ -137,6 +158,10 @@ class BBCode extends FormatterExtension { | ||||
| 		return $text; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $text | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	private function insert_code(/*string*/ $text) { | ||||
| 		$l1 = strlen("[code!]"); | ||||
| 		$l2 = strlen("[/code!]"); | ||||
|  | ||||
| @ -8,3 +8,9 @@ BLOCKQUOTE { | ||||
| 	padding: 8px; | ||||
| 	background: #DDD; | ||||
| } | ||||
| .anchor A.alink { | ||||
| 	visibility: hidden; | ||||
| } | ||||
| .anchor:hover A.alink { | ||||
| 	visibility: visible; | ||||
| } | ||||
|  | ||||
| @ -71,6 +71,12 @@ class BBCodeUnitTest extends UnitTestCase { | ||||
| 			"<a href=\"mailto:spam@shishnet.org\">spam@shishnet.org</a>"); | ||||
| 	} | ||||
| 
 | ||||
| 	public function testAnchor() { | ||||
| 		$this->assertEqual( | ||||
| 			$this->filter("[anchor=rules]Rules[/anchor]"), | ||||
| 			'<span class="anchor">Rules <a class="alink" href="#bb-rules" name="bb-rules" title="link to this anchor"> ¶ </a></span>'); | ||||
| 	} | ||||
| 
 | ||||
| 	private function filter($in) { | ||||
| 		$bb = new BBCode(); | ||||
| 		return $bb->format($in); | ||||
|  | ||||
| @ -32,7 +32,7 @@ class Blocks extends Extension { | ||||
| 	} | ||||
| 
 | ||||
| 	public function onPageRequest(PageRequestEvent $event) { | ||||
| 		global $config, $database, $page, $user; | ||||
| 		global $database, $page, $user; | ||||
| 
 | ||||
| 		$blocks = $database->cache->get("blocks"); | ||||
| 		if($blocks === false) { | ||||
|  | ||||
| @ -4,7 +4,6 @@ $kioskMode = false; | ||||
| 
 | ||||
| include '../php/filestorage.class.php'; | ||||
| include '../preferences.php'; | ||||
| include '../php/json.class.php'; | ||||
| include '../php/functions.php'; | ||||
| include '../php/yshout.class.php'; | ||||
| include '../php/ajaxcall.class.php'; | ||||
| @ -41,7 +40,7 @@ function doLogin() { | ||||
| 			'html' => cp() | ||||
| 		); | ||||
| 		 | ||||
| 		echo jsonEncode($result); | ||||
| 		echo json_encode($result); | ||||
| 		return; | ||||
| 	} | ||||
| 	 | ||||
| @ -53,7 +52,7 @@ function doLogin() { | ||||
| 	} else | ||||
| 		$result['error'] = 'invalid'; | ||||
| 
 | ||||
| 	echo jsonEncode($result); | ||||
| 	echo json_encode($result); | ||||
| } | ||||
| 
 | ||||
| function doLogout() { | ||||
| @ -63,7 +62,7 @@ function doLogout() { | ||||
| 		'error' => false | ||||
| 	); | ||||
| 
 | ||||
| 	echo jsonEncode($result); | ||||
| 	echo json_encode($result); | ||||
| } | ||||
| 
 | ||||
| function doUnban() { | ||||
| @ -74,7 +73,7 @@ function doUnban() { | ||||
| 			'error' => false | ||||
| 		); | ||||
| 		 | ||||
| 		echo jsonEncode($result); | ||||
| 		echo json_encode($result); | ||||
| 		return; | ||||
| 	} | ||||
| 	 | ||||
| @ -92,7 +91,7 @@ function doUnban() { | ||||
| 		$result['error'] = 'notbanned'; | ||||
| 
 | ||||
| 
 | ||||
| 	echo jsonEncode($result); | ||||
| 	echo json_encode($result); | ||||
| } | ||||
| 
 | ||||
| function doUnbanAll() { | ||||
| @ -103,7 +102,7 @@ function doUnbanAll() { | ||||
| 			'error' => false | ||||
| 		); | ||||
| 		 | ||||
| 		echo jsonEncode($result); | ||||
| 		echo json_encode($result); | ||||
| 		return; | ||||
| 	} | ||||
| 	 | ||||
| @ -116,7 +115,7 @@ function doUnbanAll() { | ||||
| 		'error' => false | ||||
| 	); | ||||
| 
 | ||||
| 	echo jsonEncode($result); | ||||
| 	echo json_encode($result); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| @ -128,7 +127,7 @@ function doSetPreference() { | ||||
| 			'error' => false | ||||
| 		); | ||||
| 		 | ||||
| 		echo jsonEncode($result); | ||||
| 		echo json_encode($result); | ||||
| 		return; | ||||
| 	} | ||||
| 	 | ||||
| @ -150,7 +149,7 @@ function doSetPreference() { | ||||
| 		'error' => false | ||||
| 	); | ||||
| 
 | ||||
| 	echo jsonEncode($result); | ||||
| 	echo json_encode($result); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| @ -162,7 +161,7 @@ function doResetPreferences() { | ||||
| 			'error' => false | ||||
| 		); | ||||
| 		 | ||||
| 		echo jsonEncode($result); | ||||
| 		echo json_encode($result); | ||||
| 		return; | ||||
| 	} | ||||
| 	 | ||||
| @ -177,7 +176,7 @@ function doResetPreferences() { | ||||
| 		'prefs' => $prefs | ||||
| 	); | ||||
| 
 | ||||
| 	echo jsonEncode($result); | ||||
| 	echo json_encode($result); | ||||
| } | ||||
| 
 | ||||
| /* CP Display */ | ||||
| @ -456,4 +455,3 @@ function about() { | ||||
| 	return $html; | ||||
| } | ||||
| 
 | ||||
| ?>
 | ||||
| @ -3,7 +3,6 @@ | ||||
| 
 | ||||
| 	include '../php/filestorage.class.php'; | ||||
| 	include '../preferences.php'; | ||||
| 	include '../php/json.class.php'; | ||||
| 	include '../php/functions.php'; | ||||
| 	include '../php/yshout.class.php'; | ||||
| 
 | ||||
|  | ||||
| @ -2,9 +2,7 @@ | ||||
| 	$null = null; | ||||
| 	include 'php/filestorage.class.php'; | ||||
| 	include 'preferences.php'; | ||||
| 	include 'php/json.class.php'; | ||||
| 	include 'php/functions.php'; | ||||
| 	include 'php/yshout.class.php'; | ||||
| 	include 'php/ajaxcall.class.php'; | ||||
| 
 | ||||
| ?>
 | ||||
| @ -95,7 +95,7 @@ | ||||
| 					$send['error'] = false; | ||||
| 			} | ||||
| 
 | ||||
| 			echo jsonEncode($send); | ||||
| 			echo json_encode($send); | ||||
| 		} | ||||
| 
 | ||||
| 		function doUnban() { | ||||
| @ -115,7 +115,7 @@ | ||||
| 					$send['error'] = false; | ||||
| 			} | ||||
| 
 | ||||
| 			echo jsonEncode($send); | ||||
| 			echo json_encode($send); | ||||
| 		} | ||||
| 
 | ||||
| 		function doDelete() { | ||||
| @ -132,7 +132,7 @@ | ||||
| 					$send['error'] = false; | ||||
| 			} | ||||
| 
 | ||||
| 			echo jsonEncode($send); | ||||
| 			echo json_encode($send); | ||||
| 		} | ||||
| 
 | ||||
| 		function banSelf() { | ||||
| @ -143,7 +143,7 @@ | ||||
| 			$send = array(); | ||||
| 			$send['error'] = false; | ||||
| 			 | ||||
| 			echo jsonEncode($send); | ||||
| 			echo json_encode($send); | ||||
| 		} | ||||
| 
 | ||||
| 		function unbanSelf() { | ||||
| @ -158,7 +158,7 @@ | ||||
| 				$send['error'] = 'admin'; | ||||
| 			} | ||||
| 			 | ||||
| 			echo jsonEncode($send); | ||||
| 			echo json_encode($send); | ||||
| 		} | ||||
| 		 | ||||
| 		function reload() { | ||||
| @ -168,7 +168,7 @@ | ||||
| 			$posts = $ys->latestPosts($prefs['truncate']); | ||||
| 			$this->setSessTimestamp($posts); | ||||
| 			$this->updates['posts'] = $posts;						 | ||||
| 			echo jsonEncode($this->updates); | ||||
| 			echo json_encode($this->updates); | ||||
| 		} | ||||
| 
 | ||||
| 		function initSession() { | ||||
| @ -186,7 +186,7 @@ | ||||
| 				'banned' => true | ||||
| 			); | ||||
| 
 | ||||
| 			echo jsonEncode($this->updates); | ||||
| 			echo json_encode($this->updates); | ||||
| 		} | ||||
| 		 | ||||
| 		function sendUpdates() { | ||||
| @ -199,7 +199,7 @@ | ||||
| 
 | ||||
| 			$this->updates['posts'] = $posts; | ||||
| 
 | ||||
| 			echo jsonEncode($this->updates); | ||||
| 			echo json_encode($this->updates); | ||||
| 		} | ||||
| 
 | ||||
| 		function setSessTimestamp(&$posts) { | ||||
| @ -231,7 +231,7 @@ | ||||
| 			if ($ys->banned(ip())) | ||||
| 				$this->updates['banned'] = true; | ||||
| 
 | ||||
| 			echo jsonEncode($this->updates); | ||||
| 			echo json_encode($this->updates); | ||||
| 		} | ||||
| 		 | ||||
| 		function cleanPrefs($prefs) { | ||||
| @ -253,7 +253,7 @@ | ||||
| 					$send['error'] = false; | ||||
| 			} | ||||
| 
 | ||||
| 			echo jsonEncode($send); | ||||
| 			echo json_encode($send); | ||||
| 		} | ||||
| 		 | ||||
| 		function clearLogs() { | ||||
| @ -277,7 +277,7 @@ | ||||
| 					$send['error'] = false; | ||||
| 			} | ||||
| 
 | ||||
| 			echo jsonEncode($send); | ||||
| 			echo json_encode($send); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|  | ||||
| @ -45,19 +45,6 @@ | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	function jsonEncode(&$array) { | ||||
| 		if ($array) { | ||||
| 			$json = new Services_JSON(SERVICES_JSON_LOOSE_TYPE); | ||||
| 			return $json->encode($array); | ||||
| 		} else | ||||
| 			return 'ar'; | ||||
| 	} | ||||
| 
 | ||||
| 	function jsonDecode($encoded) { | ||||
| 		$json = new Services_JSON(SERVICES_JSON_LOOSE_TYPE); | ||||
| 		return $json->decode($encoded); | ||||
| 	} | ||||
| 
 | ||||
| 	function validIP($ip) { | ||||
| 		if ($ip == long2ip(ip2long($ip))) | ||||
| 			return true; | ||||
|  | ||||
| @ -1,805 +0,0 @@ | ||||
| <?php | ||||
| /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ | ||||
| 
 | ||||
| /** | ||||
| * Converts to and from JSON format. | ||||
| * | ||||
| * JSON (JavaScript Object Notation) is a lightweight data-interchange | ||||
| * format. It is easy for humans to read and write. It is easy for machines | ||||
| * to parse and generate. It is based on a subset of the JavaScript | ||||
| * Programming Language, Standard ECMA-262 3rd Edition - December 1999. | ||||
| * This feature can also be found in  Python. JSON is a text format that is | ||||
| * completely language independent but uses conventions that are familiar | ||||
| * to programmers of the C-family of languages, including C, C++, C#, Java,
 | ||||
| * JavaScript, Perl, TCL, and many others. These properties make JSON an | ||||
| * ideal data-interchange language. | ||||
| * | ||||
| * This package provides a simple encoder and decoder for JSON notation. It | ||||
| * is intended for use with client-side Javascript applications that make | ||||
| * use of HTTPRequest to perform server communication functions - data can | ||||
| * be encoded into JSON notation for use in a client-side javascript, or | ||||
| * decoded from incoming Javascript requests. JSON format is native to | ||||
| * Javascript, and can be directly eval()'ed with no further parsing | ||||
| * overhead | ||||
| * | ||||
| * All strings should be in ASCII or UTF-8 format! | ||||
| * | ||||
| * LICENSE: Redistribution and use in source and binary forms, with or | ||||
| * without modification, are permitted provided that the following | ||||
| * conditions are met: Redistributions of source code must retain the | ||||
| * above copyright notice, this list of conditions and the following | ||||
| * disclaimer. Redistributions in binary form must reproduce the above | ||||
| * copyright notice, this list of conditions and the following disclaimer | ||||
| * in the documentation and/or other materials provided with the | ||||
| * distribution. | ||||
| * | ||||
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||||
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||||
| * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | ||||
| * NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | ||||
| * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | ||||
| * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS | ||||
| * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR | ||||
| * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE | ||||
| * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | ||||
| * DAMAGE. | ||||
| * | ||||
| * @category | ||||
| * @package     Services_JSON | ||||
| * @author      Michal Migurski <mike-json@teczno.com> | ||||
| * @author      Matt Knapp <mdknapp[at]gmail[dot]com> | ||||
| * @author      Brett Stimmerman <brettstimmerman[at]gmail[dot]com> | ||||
| * @copyright   2005 Michal Migurski | ||||
| * @version     CVS: $Id: JSON.php,v 1.30 2006/03/08 16:10:20 migurski Exp $ | ||||
| * @license     http://www.opensource.org/licenses/bsd-license.php | ||||
| * @link        http://pear.php.net/pepr/pepr-proposal-show.php?id=198 | ||||
| */ | ||||
| 
 | ||||
| /** | ||||
| * Marker constant for Services_JSON::decode(), used to flag stack state | ||||
| */ | ||||
| define('SERVICES_JSON_SLICE',   1); | ||||
| 
 | ||||
| /** | ||||
| * Marker constant for Services_JSON::decode(), used to flag stack state | ||||
| */ | ||||
| define('SERVICES_JSON_IN_STR',  2); | ||||
| 
 | ||||
| /** | ||||
| * Marker constant for Services_JSON::decode(), used to flag stack state | ||||
| */ | ||||
| define('SERVICES_JSON_IN_ARR',  3); | ||||
| 
 | ||||
| /** | ||||
| * Marker constant for Services_JSON::decode(), used to flag stack state | ||||
| */ | ||||
| define('SERVICES_JSON_IN_OBJ',  4); | ||||
| 
 | ||||
| /** | ||||
| * Marker constant for Services_JSON::decode(), used to flag stack state | ||||
| */ | ||||
| define('SERVICES_JSON_IN_CMT', 5); | ||||
| 
 | ||||
| /** | ||||
| * Behavior switch for Services_JSON::decode() | ||||
| */ | ||||
| define('SERVICES_JSON_LOOSE_TYPE', 16); | ||||
| 
 | ||||
| /** | ||||
| * Behavior switch for Services_JSON::decode() | ||||
| */ | ||||
| define('SERVICES_JSON_SUPPRESS_ERRORS', 32); | ||||
| 
 | ||||
| /** | ||||
| * Converts to and from JSON format. | ||||
| * | ||||
| * Brief example of use: | ||||
| * | ||||
| * <code> | ||||
| * // create a new instance of Services_JSON
 | ||||
| * $json = new Services_JSON(); | ||||
| * | ||||
| * // convert a complexe value to JSON notation, and send it to the browser
 | ||||
| * $value = array('foo', 'bar', array(1, 2, 'baz'), array(3, array(4))); | ||||
| * $output = $json->encode($value); | ||||
| * | ||||
| * print($output); | ||||
| * // prints: ["foo","bar",[1,2,"baz"],[3,[4]]]
 | ||||
| * | ||||
| * // accept incoming POST data, assumed to be in JSON notation
 | ||||
| * $input = file_get_contents('php://input', 1000000); | ||||
| * $value = $json->decode($input); | ||||
| * </code> | ||||
| */ | ||||
| class Services_JSON | ||||
| { | ||||
|    /** | ||||
|     * constructs a new JSON instance | ||||
|     * | ||||
|     * @param    int     $use    object behavior flags; combine with boolean-OR | ||||
|     * | ||||
|     *                           possible values: | ||||
|     *                           - SERVICES_JSON_LOOSE_TYPE:  loose typing. | ||||
|     *                                   "{...}" syntax creates associative arrays | ||||
|     *                                   instead of objects in decode(). | ||||
|     *                           - SERVICES_JSON_SUPPRESS_ERRORS:  error suppression. | ||||
|     *                                   Values which can't be encoded (e.g. resources) | ||||
|     *                                   appear as NULL instead of throwing errors. | ||||
|     *                                   By default, a deeply-nested resource will | ||||
|     *                                   bubble up with an error, so all return values | ||||
|     *                                   from encode() should be checked with isError() | ||||
|     */ | ||||
|     function Services_JSON($use = 0) | ||||
|     { | ||||
|         $this->use = $use; | ||||
|     } | ||||
| 
 | ||||
|    /** | ||||
|     * convert a string from one UTF-16 char to one UTF-8 char | ||||
|     * | ||||
|     * Normally should be handled by mb_convert_encoding, but | ||||
|     * provides a slower PHP-only method for installations | ||||
|     * that lack the multibye string extension. | ||||
|     * | ||||
|     * @param    string  $utf16  UTF-16 character | ||||
|     * @return   string  UTF-8 character | ||||
|     * @access   private | ||||
|     */ | ||||
|     function utf162utf8($utf16) | ||||
|     { | ||||
|         // oh please oh please oh please oh please oh please
 | ||||
|         if(function_exists('mb_convert_encoding')) { | ||||
|             return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16'); | ||||
|         } | ||||
| 
 | ||||
|         $bytes = (ord($utf16{0}) << 8) | ord($utf16{1}); | ||||
| 
 | ||||
|         switch(true) { | ||||
|             case ((0x7F & $bytes) == $bytes): | ||||
|                 // this case should never be reached, because we are in ASCII range
 | ||||
|                 // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
 | ||||
|                 return chr(0x7F & $bytes); | ||||
| 
 | ||||
|             case (0x07FF & $bytes) == $bytes: | ||||
|                 // return a 2-byte UTF-8 character
 | ||||
|                 // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
 | ||||
|                 return chr(0xC0 | (($bytes >> 6) & 0x1F)) | ||||
|                      . chr(0x80 | ($bytes & 0x3F)); | ||||
| 
 | ||||
|             case (0xFFFF & $bytes) == $bytes: | ||||
|                 // return a 3-byte UTF-8 character
 | ||||
|                 // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
 | ||||
|                 return chr(0xE0 | (($bytes >> 12) & 0x0F)) | ||||
|                      . chr(0x80 | (($bytes >> 6) & 0x3F)) | ||||
|                      . chr(0x80 | ($bytes & 0x3F)); | ||||
|         } | ||||
| 
 | ||||
|         // ignoring UTF-32 for now, sorry
 | ||||
|         return ''; | ||||
|     } | ||||
| 
 | ||||
|    /** | ||||
|     * convert a string from one UTF-8 char to one UTF-16 char | ||||
|     * | ||||
|     * Normally should be handled by mb_convert_encoding, but | ||||
|     * provides a slower PHP-only method for installations | ||||
|     * that lack the multibye string extension. | ||||
|     * | ||||
|     * @param    string  $utf8   UTF-8 character | ||||
|     * @return   string  UTF-16 character | ||||
|     * @access   private | ||||
|     */ | ||||
|     function utf82utf16($utf8) | ||||
|     { | ||||
|         // oh please oh please oh please oh please oh please
 | ||||
|         if(function_exists('mb_convert_encoding')) { | ||||
|             return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8'); | ||||
|         } | ||||
| 
 | ||||
|         switch(strlen($utf8)) { | ||||
|             case 1: | ||||
|                 // this case should never be reached, because we are in ASCII range
 | ||||
|                 // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
 | ||||
|                 return $utf8; | ||||
| 
 | ||||
|             case 2: | ||||
|                 // return a UTF-16 character from a 2-byte UTF-8 char
 | ||||
|                 // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
 | ||||
|                 return chr(0x07 & (ord($utf8{0}) >> 2)) | ||||
|                      . chr((0xC0 & (ord($utf8{0}) << 6)) | ||||
|                          | (0x3F & ord($utf8{1}))); | ||||
| 
 | ||||
|             case 3: | ||||
|                 // return a UTF-16 character from a 3-byte UTF-8 char
 | ||||
|                 // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
 | ||||
|                 return chr((0xF0 & (ord($utf8{0}) << 4)) | ||||
|                          | (0x0F & (ord($utf8{1}) >> 2))) | ||||
|                      . chr((0xC0 & (ord($utf8{1}) << 6)) | ||||
|                          | (0x7F & ord($utf8{2}))); | ||||
|         } | ||||
| 
 | ||||
|         // ignoring UTF-32 for now, sorry
 | ||||
|         return ''; | ||||
|     } | ||||
| 
 | ||||
|    /** | ||||
|     * encodes an arbitrary variable into JSON format | ||||
|     * | ||||
|     * @param    mixed   $var    any number, boolean, string, array, or object to be encoded. | ||||
|     *                           see argument 1 to Services_JSON() above for array-parsing behavior. | ||||
|     *                           if var is a strng, note that encode() always expects it | ||||
|     *                           to be in ASCII or UTF-8 format! | ||||
|     * | ||||
|     * @return   mixed   JSON string representation of input var or an error if a problem occurs | ||||
|     * @access   public | ||||
|     */ | ||||
|     function encode($var) | ||||
|     { | ||||
|         switch (gettype($var)) { | ||||
|             case 'boolean': | ||||
|                 return $var ? 'true' : 'false'; | ||||
| 
 | ||||
|             case 'NULL': | ||||
|                 return 'null'; | ||||
| 
 | ||||
|             case 'integer': | ||||
|                 return (int) $var; | ||||
| 
 | ||||
|             case 'double': | ||||
|             case 'float': | ||||
|                 return (float) $var; | ||||
| 
 | ||||
|             case 'string': | ||||
|                 // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT
 | ||||
|                 $ascii = ''; | ||||
|                 $strlen_var = strlen($var); | ||||
| 
 | ||||
|                /* | ||||
|                 * Iterate over every character in the string, | ||||
|                 * escaping with a slash or encoding to UTF-8 where necessary | ||||
|                 */ | ||||
|                 for ($c = 0; $c < $strlen_var; ++$c) { | ||||
| 
 | ||||
|                     $ord_var_c = ord($var{$c}); | ||||
| 
 | ||||
|                     switch (true) { | ||||
|                         case $ord_var_c == 0x08: | ||||
|                             $ascii .= '\b'; | ||||
|                             break; | ||||
|                         case $ord_var_c == 0x09: | ||||
|                             $ascii .= '\t'; | ||||
|                             break; | ||||
|                         case $ord_var_c == 0x0A: | ||||
|                             $ascii .= '\n'; | ||||
|                             break; | ||||
|                         case $ord_var_c == 0x0C: | ||||
|                             $ascii .= '\f'; | ||||
|                             break; | ||||
|                         case $ord_var_c == 0x0D: | ||||
|                             $ascii .= '\r'; | ||||
|                             break; | ||||
| 
 | ||||
|                         case $ord_var_c == 0x22: | ||||
|                         case $ord_var_c == 0x2F: | ||||
|                         case $ord_var_c == 0x5C: | ||||
|                             // double quote, slash, slosh
 | ||||
|                             $ascii .= '\\'.$var{$c}; | ||||
|                             break; | ||||
| 
 | ||||
|                         case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)): | ||||
|                             // characters U-00000000 - U-0000007F (same as ASCII)
 | ||||
|                             $ascii .= $var{$c}; | ||||
|                             break; | ||||
| 
 | ||||
|                         case (($ord_var_c & 0xE0) == 0xC0): | ||||
|                             // characters U-00000080 - U-000007FF, mask 110XXXXX
 | ||||
|                             // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
 | ||||
|                             $char = pack('C*', $ord_var_c, ord($var{$c + 1})); | ||||
|                             $c += 1; | ||||
|                             $utf16 = $this->utf82utf16($char); | ||||
|                             $ascii .= sprintf('\u%04s', bin2hex($utf16)); | ||||
|                             break; | ||||
| 
 | ||||
|                         case (($ord_var_c & 0xF0) == 0xE0): | ||||
|                             // characters U-00000800 - U-0000FFFF, mask 1110XXXX
 | ||||
|                             // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
 | ||||
|                             $char = pack('C*', $ord_var_c, | ||||
|                                          ord($var{$c + 1}), | ||||
|                                          ord($var{$c + 2})); | ||||
|                             $c += 2; | ||||
|                             $utf16 = $this->utf82utf16($char); | ||||
|                             $ascii .= sprintf('\u%04s', bin2hex($utf16)); | ||||
|                             break; | ||||
| 
 | ||||
|                         case (($ord_var_c & 0xF8) == 0xF0): | ||||
|                             // characters U-00010000 - U-001FFFFF, mask 11110XXX
 | ||||
|                             // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
 | ||||
|                             $char = pack('C*', $ord_var_c, | ||||
|                                          ord($var{$c + 1}), | ||||
|                                          ord($var{$c + 2}), | ||||
|                                          ord($var{$c + 3})); | ||||
|                             $c += 3; | ||||
|                             $utf16 = $this->utf82utf16($char); | ||||
|                             $ascii .= sprintf('\u%04s', bin2hex($utf16)); | ||||
|                             break; | ||||
| 
 | ||||
|                         case (($ord_var_c & 0xFC) == 0xF8): | ||||
|                             // characters U-00200000 - U-03FFFFFF, mask 111110XX
 | ||||
|                             // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
 | ||||
|                             $char = pack('C*', $ord_var_c, | ||||
|                                          ord($var{$c + 1}), | ||||
|                                          ord($var{$c + 2}), | ||||
|                                          ord($var{$c + 3}), | ||||
|                                          ord($var{$c + 4})); | ||||
|                             $c += 4; | ||||
|                             $utf16 = $this->utf82utf16($char); | ||||
|                             $ascii .= sprintf('\u%04s', bin2hex($utf16)); | ||||
|                             break; | ||||
| 
 | ||||
|                         case (($ord_var_c & 0xFE) == 0xFC): | ||||
|                             // characters U-04000000 - U-7FFFFFFF, mask 1111110X
 | ||||
|                             // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
 | ||||
|                             $char = pack('C*', $ord_var_c, | ||||
|                                          ord($var{$c + 1}), | ||||
|                                          ord($var{$c + 2}), | ||||
|                                          ord($var{$c + 3}), | ||||
|                                          ord($var{$c + 4}), | ||||
|                                          ord($var{$c + 5})); | ||||
|                             $c += 5; | ||||
|                             $utf16 = $this->utf82utf16($char); | ||||
|                             $ascii .= sprintf('\u%04s', bin2hex($utf16)); | ||||
|                             break; | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 return '"'.$ascii.'"'; | ||||
| 
 | ||||
|             case 'array': | ||||
|                /* | ||||
|                 * As per JSON spec if any array key is not an integer | ||||
|                 * we must treat the the whole array as an object. We | ||||
|                 * also try to catch a sparsely populated associative | ||||
|                 * array with numeric keys here because some JS engines | ||||
|                 * will create an array with empty indexes up to | ||||
|                 * max_index which can cause memory issues and because | ||||
|                 * the keys, which may be relevant, will be remapped | ||||
|                 * otherwise. | ||||
|                 * | ||||
|                 * As per the ECMA and JSON specification an object may | ||||
|                 * have any string as a property. Unfortunately due to | ||||
|                 * a hole in the ECMA specification if the key is a | ||||
|                 * ECMA reserved word or starts with a digit the | ||||
|                 * parameter is only accessible using ECMAScript's | ||||
|                 * bracket notation. | ||||
|                 */ | ||||
| 
 | ||||
|                 // treat as a JSON object
 | ||||
|                 if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) { | ||||
|                     $properties = array_map(array($this, 'name_value'), | ||||
|                                             array_keys($var), | ||||
|                                             array_values($var)); | ||||
| 
 | ||||
|                     foreach($properties as $property) { | ||||
|                         if(Services_JSON::isError($property)) { | ||||
|                             return $property; | ||||
|                         } | ||||
|                     } | ||||
| 
 | ||||
|                     return '{' . join(',', $properties) . '}'; | ||||
|                 } | ||||
| 
 | ||||
|                 // treat it like a regular array
 | ||||
|                 $elements = array_map(array($this, 'encode'), $var); | ||||
| 
 | ||||
|                 foreach($elements as $element) { | ||||
|                     if(Services_JSON::isError($element)) { | ||||
|                         return $element; | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 return '[' . join(',', $elements) . ']'; | ||||
| 
 | ||||
|             case 'object': | ||||
|                 $vars = get_object_vars($var); | ||||
| 
 | ||||
|                 $properties = array_map(array($this, 'name_value'), | ||||
|                                         array_keys($vars), | ||||
|                                         array_values($vars)); | ||||
| 
 | ||||
|                 foreach($properties as $property) { | ||||
|                     if(Services_JSON::isError($property)) { | ||||
|                         return $property; | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 return '{' . join(',', $properties) . '}'; | ||||
| 
 | ||||
|             default: | ||||
|                 return ($this->use & SERVICES_JSON_SUPPRESS_ERRORS) | ||||
|                     ? 'null' | ||||
|                     : new Services_JSON_Error(gettype($var)." can not be encoded as JSON string"); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|    /** | ||||
|     * array-walking function for use in generating JSON-formatted name-value pairs | ||||
|     * | ||||
|     * @param    string  $name   name of key to use | ||||
|     * @param    mixed   $value  reference to an array element to be encoded | ||||
|     * | ||||
|     * @return   string  JSON-formatted name-value pair, like '"name":value' | ||||
|     * @access   private | ||||
|     */ | ||||
|     function name_value($name, $value) | ||||
|     { | ||||
|         $encoded_value = $this->encode($value); | ||||
| 
 | ||||
|         if(Services_JSON::isError($encoded_value)) { | ||||
|             return $encoded_value; | ||||
|         } | ||||
| 
 | ||||
|         return $this->encode(strval($name)) . ':' . $encoded_value; | ||||
|     } | ||||
| 
 | ||||
|    /** | ||||
|     * reduce a string by removing leading and trailing comments and whitespace | ||||
|     * | ||||
|     * @param    $str    string      string value to strip of comments and whitespace | ||||
|     * | ||||
|     * @return   string  string value stripped of comments and whitespace | ||||
|     * @access   private | ||||
|     */ | ||||
|     function reduce_string($str) | ||||
|     { | ||||
|         $str = preg_replace(array( | ||||
| 
 | ||||
|                 // eliminate single line comments in '// ...' form
 | ||||
|                 '#^\s*//(.+)$#m', | ||||
| 
 | ||||
|                 // eliminate multi-line comments in '/* ... */' form, at start of string
 | ||||
|                 '#^\s*/\*(.+)\*/#Us', | ||||
| 
 | ||||
|                 // eliminate multi-line comments in '/* ... */' form, at end of string
 | ||||
|                 '#/\*(.+)\*/\s*$#Us' | ||||
| 
 | ||||
|             ), '', $str); | ||||
| 
 | ||||
|         // eliminate extraneous space
 | ||||
|         return trim($str); | ||||
|     } | ||||
| 
 | ||||
|    /** | ||||
|     * decodes a JSON string into appropriate variable | ||||
|     * | ||||
|     * @param    string  $str    JSON-formatted string | ||||
|     * | ||||
|     * @return   mixed   number, boolean, string, array, or object | ||||
|     *                   corresponding to given JSON input string. | ||||
|     *                   See argument 1 to Services_JSON() above for object-output behavior. | ||||
|     *                   Note that decode() always returns strings | ||||
|     *                   in ASCII or UTF-8 format! | ||||
|     * @access   public | ||||
|     */ | ||||
|     function decode($str) | ||||
|     { | ||||
|         $str = $this->reduce_string($str); | ||||
| 
 | ||||
|         switch (strtolower($str)) { | ||||
|             case 'true': | ||||
|                 return true; | ||||
| 
 | ||||
|             case 'false': | ||||
|                 return false; | ||||
| 
 | ||||
|             case 'null': | ||||
|                 return null; | ||||
| 
 | ||||
|             default: | ||||
|                 $m = array(); | ||||
| 
 | ||||
|                 if (is_numeric($str)) { | ||||
|                     // Lookie-loo, it's a number
 | ||||
| 
 | ||||
|                     // This would work on its own, but I'm trying to be
 | ||||
|                     // good about returning integers where appropriate:
 | ||||
|                     // return (float)$str;
 | ||||
| 
 | ||||
|                     // Return float or int, as appropriate
 | ||||
|                     return ((float)$str == (integer)$str) | ||||
|                         ? (integer)$str | ||||
|                         : (float)$str; | ||||
| 
 | ||||
|                 } elseif (preg_match('/^("|\').*(\1)$/s', $str, $m) && $m[1] == $m[2]) { | ||||
|                     // STRINGS RETURNED IN UTF-8 FORMAT
 | ||||
|                     $delim = substr($str, 0, 1); | ||||
|                     $chrs = substr($str, 1, -1); | ||||
|                     $utf8 = ''; | ||||
|                     $strlen_chrs = strlen($chrs); | ||||
| 
 | ||||
|                     for ($c = 0; $c < $strlen_chrs; ++$c) { | ||||
| 
 | ||||
|                         $substr_chrs_c_2 = substr($chrs, $c, 2); | ||||
|                         $ord_chrs_c = ord($chrs{$c}); | ||||
| 
 | ||||
|                         switch (true) { | ||||
|                             case $substr_chrs_c_2 == '\b': | ||||
|                                 $utf8 .= chr(0x08); | ||||
|                                 ++$c; | ||||
|                                 break; | ||||
|                             case $substr_chrs_c_2 == '\t': | ||||
|                                 $utf8 .= chr(0x09); | ||||
|                                 ++$c; | ||||
|                                 break; | ||||
|                             case $substr_chrs_c_2 == '\n': | ||||
|                                 $utf8 .= chr(0x0A); | ||||
|                                 ++$c; | ||||
|                                 break; | ||||
|                             case $substr_chrs_c_2 == '\f': | ||||
|                                 $utf8 .= chr(0x0C); | ||||
|                                 ++$c; | ||||
|                                 break; | ||||
|                             case $substr_chrs_c_2 == '\r': | ||||
|                                 $utf8 .= chr(0x0D); | ||||
|                                 ++$c; | ||||
|                                 break; | ||||
| 
 | ||||
|                             case $substr_chrs_c_2 == '\\"': | ||||
|                             case $substr_chrs_c_2 == '\\\'': | ||||
|                             case $substr_chrs_c_2 == '\\\\': | ||||
|                             case $substr_chrs_c_2 == '\\/': | ||||
|                                 if (($delim == '"' && $substr_chrs_c_2 != '\\\'') || | ||||
|                                    ($delim == "'" && $substr_chrs_c_2 != '\\"')) { | ||||
|                                     $utf8 .= $chrs{++$c}; | ||||
|                                 } | ||||
|                                 break; | ||||
| 
 | ||||
|                             case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)): | ||||
|                                 // single, escaped unicode character
 | ||||
|                                 $utf16 = chr(hexdec(substr($chrs, ($c + 2), 2))) | ||||
|                                        . chr(hexdec(substr($chrs, ($c + 4), 2))); | ||||
|                                 $utf8 .= $this->utf162utf8($utf16); | ||||
|                                 $c += 5; | ||||
|                                 break; | ||||
| 
 | ||||
|                             case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F): | ||||
|                                 $utf8 .= $chrs{$c}; | ||||
|                                 break; | ||||
| 
 | ||||
|                             case ($ord_chrs_c & 0xE0) == 0xC0: | ||||
|                                 // characters U-00000080 - U-000007FF, mask 110XXXXX
 | ||||
|                                 //see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
 | ||||
|                                 $utf8 .= substr($chrs, $c, 2); | ||||
|                                 ++$c; | ||||
|                                 break; | ||||
| 
 | ||||
|                             case ($ord_chrs_c & 0xF0) == 0xE0: | ||||
|                                 // characters U-00000800 - U-0000FFFF, mask 1110XXXX
 | ||||
|                                 // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
 | ||||
|                                 $utf8 .= substr($chrs, $c, 3); | ||||
|                                 $c += 2; | ||||
|                                 break; | ||||
| 
 | ||||
|                             case ($ord_chrs_c & 0xF8) == 0xF0: | ||||
|                                 // characters U-00010000 - U-001FFFFF, mask 11110XXX
 | ||||
|                                 // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
 | ||||
|                                 $utf8 .= substr($chrs, $c, 4); | ||||
|                                 $c += 3; | ||||
|                                 break; | ||||
| 
 | ||||
|                             case ($ord_chrs_c & 0xFC) == 0xF8: | ||||
|                                 // characters U-00200000 - U-03FFFFFF, mask 111110XX
 | ||||
|                                 // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
 | ||||
|                                 $utf8 .= substr($chrs, $c, 5); | ||||
|                                 $c += 4; | ||||
|                                 break; | ||||
| 
 | ||||
|                             case ($ord_chrs_c & 0xFE) == 0xFC: | ||||
|                                 // characters U-04000000 - U-7FFFFFFF, mask 1111110X
 | ||||
|                                 // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
 | ||||
|                                 $utf8 .= substr($chrs, $c, 6); | ||||
|                                 $c += 5; | ||||
|                                 break; | ||||
| 
 | ||||
|                         } | ||||
| 
 | ||||
|                     } | ||||
| 
 | ||||
|                     return $utf8; | ||||
| 
 | ||||
|                 } elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) { | ||||
|                     // array, or object notation
 | ||||
| 
 | ||||
|                     if ($str{0} == '[') { | ||||
|                         $stk = array(SERVICES_JSON_IN_ARR); | ||||
|                         $arr = array(); | ||||
|                     } else { | ||||
|                         if ($this->use & SERVICES_JSON_LOOSE_TYPE) { | ||||
|                             $stk = array(SERVICES_JSON_IN_OBJ); | ||||
|                             $obj = array(); | ||||
|                         } else { | ||||
|                             $stk = array(SERVICES_JSON_IN_OBJ); | ||||
|                             $obj = new stdClass(); | ||||
|                         } | ||||
|                     } | ||||
| 
 | ||||
|                     array_push($stk, array('what'  => SERVICES_JSON_SLICE, | ||||
|                                            'where' => 0, | ||||
|                                            'delim' => false)); | ||||
| 
 | ||||
|                     $chrs = substr($str, 1, -1); | ||||
|                     $chrs = $this->reduce_string($chrs); | ||||
| 
 | ||||
|                     if ($chrs == '') { | ||||
|                         if (reset($stk) == SERVICES_JSON_IN_ARR) { | ||||
|                             return $arr; | ||||
| 
 | ||||
|                         } else { | ||||
|                             return $obj; | ||||
| 
 | ||||
|                         } | ||||
|                     } | ||||
| 
 | ||||
|                     //print("\nparsing {$chrs}\n");
 | ||||
| 
 | ||||
|                     $strlen_chrs = strlen($chrs); | ||||
| 
 | ||||
|                     for ($c = 0; $c <= $strlen_chrs; ++$c) { | ||||
| 
 | ||||
|                         $top = end($stk); | ||||
|                         $substr_chrs_c_2 = substr($chrs, $c, 2); | ||||
| 
 | ||||
|                         if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == SERVICES_JSON_SLICE))) { | ||||
|                             // found a comma that is not inside a string, array, etc.,
 | ||||
|                             // OR we've reached the end of the character list
 | ||||
|                             $slice = substr($chrs, $top['where'], ($c - $top['where'])); | ||||
|                             array_push($stk, array('what' => SERVICES_JSON_SLICE, 'where' => ($c + 1), 'delim' => false)); | ||||
|                             //print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
 | ||||
| 
 | ||||
|                             if (reset($stk) == SERVICES_JSON_IN_ARR) { | ||||
|                                 // we are in an array, so just push an element onto the stack
 | ||||
|                                 array_push($arr, $this->decode($slice)); | ||||
| 
 | ||||
|                             } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) { | ||||
|                                 // we are in an object, so figure
 | ||||
|                                 // out the property name and set an
 | ||||
|                                 // element in an associative array,
 | ||||
|                                 // for now
 | ||||
|                                 $parts = array(); | ||||
|                                  | ||||
|                                 if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) { | ||||
|                                     // "name":value pair
 | ||||
|                                     $key = $this->decode($parts[1]); | ||||
|                                     $val = $this->decode($parts[2]); | ||||
| 
 | ||||
|                                     if ($this->use & SERVICES_JSON_LOOSE_TYPE) { | ||||
|                                         $obj[$key] = $val; | ||||
|                                     } else { | ||||
|                                         $obj->$key = $val; | ||||
|                                     } | ||||
|                                 } elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) { | ||||
|                                     // name:value pair, where name is unquoted
 | ||||
|                                     $key = $parts[1]; | ||||
|                                     $val = $this->decode($parts[2]); | ||||
| 
 | ||||
|                                     if ($this->use & SERVICES_JSON_LOOSE_TYPE) { | ||||
|                                         $obj[$key] = $val; | ||||
|                                     } else { | ||||
|                                         $obj->$key = $val; | ||||
|                                     } | ||||
|                                 } | ||||
| 
 | ||||
|                             } | ||||
| 
 | ||||
|                         } elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != SERVICES_JSON_IN_STR)) { | ||||
|                             // found a quote, and we are not inside a string
 | ||||
|                             array_push($stk, array('what' => SERVICES_JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c})); | ||||
|                             //print("Found start of string at {$c}\n");
 | ||||
| 
 | ||||
|                         } elseif (($chrs{$c} == $top['delim']) && | ||||
|                                  ($top['what'] == SERVICES_JSON_IN_STR) && | ||||
|                                  (($chrs{$c - 1} != '\\') || | ||||
|                                  ($chrs{$c - 1} == '\\' && $chrs{$c - 2} == '\\'))) { | ||||
|                             // found a quote, we're in a string, and it's not escaped
 | ||||
|                             array_pop($stk); | ||||
|                             //print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n");
 | ||||
| 
 | ||||
|                         } elseif (($chrs{$c} == '[') && | ||||
|                                  in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { | ||||
|                             // found a left-bracket, and we are in an array, object, or slice
 | ||||
|                             array_push($stk, array('what' => SERVICES_JSON_IN_ARR, 'where' => $c, 'delim' => false)); | ||||
|                             //print("Found start of array at {$c}\n");
 | ||||
| 
 | ||||
|                         } elseif (($chrs{$c} == ']') && ($top['what'] == SERVICES_JSON_IN_ARR)) { | ||||
|                             // found a right-bracket, and we're in an array
 | ||||
|                             array_pop($stk); | ||||
|                             //print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
 | ||||
| 
 | ||||
|                         } elseif (($chrs{$c} == '{') && | ||||
|                                  in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { | ||||
|                             // found a left-brace, and we are in an array, object, or slice
 | ||||
|                             array_push($stk, array('what' => SERVICES_JSON_IN_OBJ, 'where' => $c, 'delim' => false)); | ||||
|                             //print("Found start of object at {$c}\n");
 | ||||
| 
 | ||||
|                         } elseif (($chrs{$c} == '}') && ($top['what'] == SERVICES_JSON_IN_OBJ)) { | ||||
|                             // found a right-brace, and we're in an object
 | ||||
|                             array_pop($stk); | ||||
|                             //print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
 | ||||
| 
 | ||||
|                         } elseif (($substr_chrs_c_2 == '/*') && | ||||
|                                  in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { | ||||
|                             // found a comment start, and we are in an array, object, or slice
 | ||||
|                             array_push($stk, array('what' => SERVICES_JSON_IN_CMT, 'where' => $c, 'delim' => false)); | ||||
|                             $c++; | ||||
|                             //print("Found start of comment at {$c}\n");
 | ||||
| 
 | ||||
|                         } elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == SERVICES_JSON_IN_CMT)) { | ||||
|                             // found a comment end, and we're in one now
 | ||||
|                             array_pop($stk); | ||||
|                             $c++; | ||||
| 
 | ||||
|                             for ($i = $top['where']; $i <= $c; ++$i) | ||||
|                                 $chrs = substr_replace($chrs, ' ', $i, 1); | ||||
| 
 | ||||
|                             //print("Found end of comment at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
 | ||||
| 
 | ||||
|                         } | ||||
| 
 | ||||
|                     } | ||||
| 
 | ||||
|                     if (reset($stk) == SERVICES_JSON_IN_ARR) { | ||||
|                         return $arr; | ||||
| 
 | ||||
|                     } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) { | ||||
|                         return $obj; | ||||
| 
 | ||||
|                     } | ||||
| 
 | ||||
|                 } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * @todo Ultimately, this should just call PEAR::isError() | ||||
|      */ | ||||
|     function isError($data, $code = null) | ||||
|     { | ||||
|         if (class_exists('pear')) { | ||||
|             return PEAR::isError($data, $code); | ||||
|         } elseif (is_object($data) && (get_class($data) == 'services_json_error' || | ||||
|                                  is_subclass_of($data, 'services_json_error'))) { | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| if (class_exists('PEAR_Error')) { | ||||
| 
 | ||||
|     class Services_JSON_Error extends PEAR_Error | ||||
|     { | ||||
|         function Services_JSON_Error($message = 'unknown error', $code = null, | ||||
|                                      $mode = null, $options = null, $userinfo = null) | ||||
|         { | ||||
|             parent::PEAR_Error($message, $code, $mode, $options, $userinfo); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } else { | ||||
| 
 | ||||
|     /** | ||||
|      * @todo Ultimately, this class shall be descended from PEAR_Error | ||||
|      */ | ||||
|     class Services_JSON_Error | ||||
|     { | ||||
|         function Services_JSON_Error($message = 'unknown error', $code = null, | ||||
|                                      $mode = null, $options = null, $userinfo = null) | ||||
|         { | ||||
| 
 | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|      | ||||
| ?>
 | ||||
| @ -246,7 +246,6 @@ class YShout { | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
| @ -1,8 +1,10 @@ | ||||
| <?php | ||||
| 
 | ||||
| error_reporting(E_ALL); | ||||
| ob_start(); | ||||
| set_error_handler('errorOccurred'); | ||||
| include 'include.php'; | ||||
| 
 | ||||
| if (isset($_POST['reqFor'])) | ||||
| 	switch($_POST['reqFor']) { | ||||
| 		case 'shout': | ||||
| @ -20,20 +22,17 @@ if (isset($_POST['reqFor'])) | ||||
| 
 | ||||
| 		default: | ||||
| 			exit; | ||||
| 	} | ||||
| else | ||||
| 	} else { | ||||
| 		include 'example.html'; | ||||
| 	} | ||||
| 
 | ||||
| function errorOccurred($num, $str, $file, $line) { | ||||
| 	$err = array ( | ||||
| 		'yError' => "$str. \n File: $file \n Line: $line" | ||||
| 	); | ||||
| 
 | ||||
| 	if (function_exists('jsonEncode')) | ||||
| 		echo jsonEncode($err); | ||||
| 	else | ||||
| 		echo $err['yError']; | ||||
| 	echo json_encode($err); | ||||
| 
 | ||||
| 	exit; | ||||
| } | ||||
| 
 | ||||
| ?>
 | ||||
| @ -12,8 +12,18 @@ | ||||
| require_once "lib/akismet.class.php"; | ||||
| 
 | ||||
| class CommentPostingEvent extends Event { | ||||
| 	var $image_id, $user, $comment; | ||||
| 	/** @var  int */ | ||||
| 	public $image_id; | ||||
| 	/** @var \User */ | ||||
| 	public $user; | ||||
| 	/** @var string  */ | ||||
| 	public $comment; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param int $image_id | ||||
| 	 * @param \User $user | ||||
| 	 * @param string $comment | ||||
| 	 */ | ||||
| 	public function __construct($image_id, $user, $comment) { | ||||
| 		$this->image_id = $image_id; | ||||
| 		$this->user = $user; | ||||
| @ -27,8 +37,12 @@ class CommentPostingEvent extends Event { | ||||
|  * and what should be kept? | ||||
|  */ | ||||
| class CommentDeletionEvent extends Event { | ||||
| 	var $comment_id; | ||||
| 	/** @var  int */ | ||||
| 	public $comment_id; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param int $comment_id | ||||
| 	 */ | ||||
| 	public function __construct($comment_id) { | ||||
| 		$this->comment_id = $comment_id; | ||||
| 	} | ||||
| @ -54,11 +68,18 @@ class Comment { | ||||
| 		$this->posted =  $row['posted']; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param \User $user | ||||
| 	 * @return mixed | ||||
| 	 */ | ||||
| 	public static function count_comments_by_user($user) { | ||||
| 		global $database; | ||||
| 		return $database->get_one("SELECT COUNT(*) AS count FROM comments WHERE owner_id=:owner_id", array("owner_id"=>$user->id)); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @return null|User | ||||
| 	 */ | ||||
| 	public function get_owner() { | ||||
| 		if(empty($this->owner)) $this->owner = User::by_id($this->owner_id); | ||||
| 		return $this->owner; | ||||
| @ -265,19 +286,20 @@ class CommentList extends Extension { | ||||
| 	} | ||||
| 
 | ||||
| 	public function onSearchTermParse(SearchTermParseEvent $event) { | ||||
| 		global $database; | ||||
| 
 | ||||
| 		$matches = array(); | ||||
| 
 | ||||
| 		if(preg_match("/^comments([:]?<|[:]?>|[:]?<=|[:]?>=|[:|=])(\d+)$/i", $event->term, $matches)) { | ||||
| 			$cmp = ltrim($matches[1], ":") ?: "="; | ||||
| 			$comments = $matches[2]; | ||||
| 			$event->add_querylet(new Querylet("images.id IN (SELECT DISTINCT image_id FROM comments GROUP BY image_id HAVING count(image_id) $cmp $comments)")); | ||||
| 		} | ||||
| 		else if(preg_match("/^commented_by[=|:](.*)$/i", $event->term, $matches)) { | ||||
| 			global $database; | ||||
| 			$user = User::by_name($matches[1]); | ||||
| 			if(!is_null($user)) { | ||||
| 				$user_id = $user->id; | ||||
| 			} | ||||
| 			else { | ||||
| 			} else { | ||||
| 				$user_id = -1; | ||||
| 			} | ||||
| 
 | ||||
| @ -290,11 +312,16 @@ class CommentList extends Extension { | ||||
| 	} | ||||
| 
 | ||||
| // page building {{{
 | ||||
| 	/** | ||||
| 	 * @param int $current_page | ||||
| 	 */ | ||||
| 	private function build_page(/*int*/ $current_page) { | ||||
| 		global $page, $config, $database, $user; | ||||
| 		global $database, $user; | ||||
| 
 | ||||
| 		if(class_exists("Ratings")) { | ||||
| 			$user_ratings = Ratings::get_user_privs($user); | ||||
| 		} else { | ||||
| 			$user_ratings = ""; | ||||
| 		} | ||||
| 
 | ||||
| 		$where = SPEED_HAX ? "WHERE posted > now() - interval '24 hours'" : ""; | ||||
| @ -341,8 +368,12 @@ class CommentList extends Extension { | ||||
| // }}}
 | ||||
| 
 | ||||
| // get comments {{{
 | ||||
| 	/** | ||||
| 	 * @param int $count | ||||
| 	 * @return array | ||||
| 	 */ | ||||
| 	private function get_recent_comments($count) { | ||||
| 		global $config, $database; | ||||
| 		global $database; | ||||
| 		$rows = $database->get_all(" | ||||
| 				SELECT | ||||
| 				users.id as user_id, users.name as user_name, users.email as user_email, users.class as user_class, | ||||
| @ -361,8 +392,14 @@ class CommentList extends Extension { | ||||
| 		return $comments; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param int $user_id | ||||
| 	 * @param int $count | ||||
| 	 * @param int $offset | ||||
| 	 * @return array | ||||
| 	 */ | ||||
| 	private function get_user_comments(/*int*/ $user_id, /*int*/ $count, /*int*/ $offset=0) { | ||||
| 		global $config, $database; | ||||
| 		global $database; | ||||
| 		$rows = $database->get_all(" | ||||
| 				SELECT | ||||
| 				users.id as user_id, users.name as user_name, users.email as user_email, users.class as user_class, | ||||
| @ -382,8 +419,12 @@ class CommentList extends Extension { | ||||
| 		return $comments; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param int $image_id | ||||
| 	 * @return array | ||||
| 	 */ | ||||
| 	private function get_comments(/*int*/ $image_id) { | ||||
| 		global $config, $database; | ||||
| 		global $database; | ||||
| 		$i_image_id = int_escape($image_id); | ||||
| 		$rows = $database->get_all(" | ||||
| 				SELECT | ||||
| @ -425,6 +466,9 @@ class CommentList extends Extension { | ||||
| 		return (count($result) >= $max); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @return bool | ||||
| 	 */ | ||||
| 	private function hash_match() { | ||||
| 		return ($_POST['hash'] == $this->get_hash()); | ||||
| 	} | ||||
| @ -440,6 +484,10 @@ class CommentList extends Extension { | ||||
| 		return md5($_SERVER['REMOTE_ADDR'] . date("%Y%m%d")); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $text | ||||
| 	 * @return bool | ||||
| 	 */ | ||||
| 	private function is_spam_akismet(/*string*/ $text) { | ||||
| 		global $config, $user; | ||||
| 		if(strlen($config->get_string('comment_wordpress_key')) > 0) { | ||||
| @ -478,11 +526,22 @@ class CommentList extends Extension { | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param int $image_id | ||||
| 	 * @param int $comment | ||||
| 	 * @return null | ||||
| 	 */ | ||||
| 	private function is_dupe(/*int*/ $image_id, /*string*/ $comment) { | ||||
| 		global $database; | ||||
| 		return ($database->get_row("SELECT * FROM comments WHERE image_id=:image_id AND comment=:comment", array("image_id"=>$image_id, "comment"=>$comment))); | ||||
| 	} | ||||
| // do some checks
 | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param int $pagenum | ||||
| 	 * @param int $maxpage | ||||
| 	 * @return int | ||||
| 	 */ | ||||
| 	private function sanity_check_pagenumber(/*int*/ $pagenum, /*int*/ $maxpage){ | ||||
| 		if (!is_numeric($pagenum)){ | ||||
| 			$pagenum=1; | ||||
| @ -496,6 +555,12 @@ class CommentList extends Extension { | ||||
| 		return $pagenum; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param int $image_id | ||||
| 	 * @param User $user | ||||
| 	 * @param string $comment | ||||
| 	 * @throws CommentPostingException | ||||
| 	 */ | ||||
| 	private function add_comment_wrapper(/*int*/ $image_id, User $user, /*string*/ $comment) { | ||||
| 		global $database, $config; | ||||
| 
 | ||||
|  | ||||
| @ -18,8 +18,12 @@ class CommentListTheme extends Themelet { | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Display a page with a list of images, and for each image, | ||||
| 	 * the image's comments | ||||
| 	 * Display a page with a list of images, and for each image, the image's comments. | ||||
| 	 * | ||||
| 	 * @param array $images | ||||
| 	 * @param int $page_number | ||||
| 	 * @param int $total_pages | ||||
| 	 * @param bool $can_post | ||||
| 	 */ | ||||
| 	public function display_comment_list($images, $page_number, $total_pages, $can_post) { | ||||
| 		global $config, $page, $user; | ||||
| @ -119,9 +123,9 @@ class CommentListTheme extends Themelet { | ||||
| 
 | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Add some comments to the page, probably in a sidebar | ||||
| 	 * Add some comments to the page, probably in a sidebar. | ||||
| 	 * | ||||
| 	 * $comments = an array of Comment objects to be shown | ||||
| 	 * @param \Comment[] $comments An array of Comment objects to be shown | ||||
| 	 */ | ||||
| 	public function display_recent_comments($comments) { | ||||
| 		global $page; | ||||
| @ -136,7 +140,11 @@ class CommentListTheme extends Themelet { | ||||
| 
 | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Show comments for an image | ||||
| 	 * Show comments for an image. | ||||
| 	 * | ||||
| 	 * @param Image $image | ||||
| 	 * @param \Comment[] $comments | ||||
| 	 * @param bool $postbox | ||||
| 	 */ | ||||
| 	public function display_image_comments(Image $image, $comments, $postbox) { | ||||
| 		global $page; | ||||
| @ -153,9 +161,12 @@ class CommentListTheme extends Themelet { | ||||
| 
 | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Show comments made by a user | ||||
| 	 * Show comments made by a user. | ||||
| 	 * | ||||
| 	 * @param \Comment[] $comments | ||||
| 	 * @param \User $user | ||||
| 	 */ | ||||
| 	public function display_recent_user_comments($comments, $user) { | ||||
| 	public function display_recent_user_comments($comments, User $user) { | ||||
| 		global $page; | ||||
| 		$html = ""; | ||||
| 		foreach($comments as $comment) { | ||||
| @ -170,7 +181,13 @@ class CommentListTheme extends Themelet { | ||||
| 		$page->add_block(new Block("Comments", $html, "left", 70, "comment-list-user")); | ||||
| 	} | ||||
| 
 | ||||
| 	public function display_all_user_comments($comments, $page_number, $total_pages, $user) { | ||||
| 	/** | ||||
| 	 * @param \Comment[] $comments | ||||
| 	 * @param int $page_number | ||||
| 	 * @param int $total_pages | ||||
| 	 * @param \User $user | ||||
| 	 */ | ||||
| 	public function display_all_user_comments($comments, $page_number, $total_pages, User $user) { | ||||
| 		global $page; | ||||
| 		 | ||||
| 		assert(is_numeric($page_number)); | ||||
| @ -203,7 +220,12 @@ class CommentListTheme extends Themelet { | ||||
| 		$this->display_paginator($page, "comment/beta-search/{$user->name}", null, $page_number, $total_pages); | ||||
| 	} | ||||
| 
 | ||||
| 	protected function comment_to_html($comment, $trim=false) { | ||||
| 	/** | ||||
| 	 * @param \Comment $comment | ||||
| 	 * @param bool $trim | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	protected function comment_to_html(Comment $comment, $trim=false) { | ||||
| 		global $config, $user; | ||||
| 
 | ||||
| 		$tfe = new TextFormattingEvent($comment->comment); | ||||
| @ -276,6 +298,10 @@ class CommentListTheme extends Themelet { | ||||
| 		return $html; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param int $image_id | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	protected function build_postbox(/*int*/ $image_id) { | ||||
| 		global $config; | ||||
| 
 | ||||
|  | ||||
| @ -30,6 +30,12 @@ class CronUploader extends Extension { | ||||
| 	 */ | ||||
| 	private $root_dir = ""; | ||||
| 	 | ||||
| 	/** | ||||
| 	 * Key used to identify uploader | ||||
| 	 * @var string | ||||
| 	 */ | ||||
| 	private $upload_key = ""; | ||||
| 	 | ||||
| 	/** | ||||
| 	 * Checks if the cron upload page has been accessed | ||||
| 	 * and initializes the upload. | ||||
| @ -39,10 +45,10 @@ class CronUploader extends Extension { | ||||
| 		global $config, $user; | ||||
| 		 | ||||
| 		if ($event->page_matches ( "cron_upload" )) { | ||||
| 			$key = $config->get_string ( "cron_uploader_key", "" ); | ||||
| 			$this->upload_key = $config->get_string ( "cron_uploader_key", "" ); | ||||
| 			 | ||||
| 			// If the key is in the url, upload
 | ||||
| 			if ($key != "" && $event->get_arg ( 0 ) == $key) { | ||||
| 			if ($this->upload_key != "" && $event->get_arg ( 0 ) == $this->upload_key) { | ||||
| 				// log in as admin
 | ||||
| 				$this->process_upload(); // Start upload
 | ||||
| 			}  | ||||
| @ -67,8 +73,8 @@ class CronUploader extends Extension { | ||||
| 		$uploaded_dirinfo = $this->scan_dir($uploaded_dir); | ||||
| 		$failed_dirinfo = $this->scan_dir($failed_dir); | ||||
| 		 | ||||
| 		$cron_url = make_http(make_link("/cron_upload/" . $config->get_string('cron_uploader_key', 'invalid key' ))); | ||||
| 		$cron_cmd = "curl -f $cron_url"; | ||||
| 		$cron_url = make_http(make_link("/cron_upload/" . $this->upload_key)); | ||||
| 		$cron_cmd = "curl --silent $cron_url"; | ||||
| 		$log_path = $this->root_dir . "/uploads.log"; | ||||
| 		 | ||||
| 		$info_html = "<b>Information</b>
 | ||||
| @ -135,19 +141,21 @@ class CronUploader extends Extension { | ||||
| 	public function onInitExt(InitExtEvent $event) { | ||||
| 		global $config; | ||||
| 		// Set default values
 | ||||
| 		$key = $this->generate_key (); | ||||
| 		if ($config->get_string("cron_uploader_key", "")) { | ||||
| 			$this->upload_key = $this->generate_key (); | ||||
| 	 | ||||
| 			$config->set_default_int ( 'cron_uploader_count', 1 ); | ||||
| 		$config->set_default_string ( 'cron_uploader_key', $key ); | ||||
| 			$config->set_default_string ( 'cron_uploader_key', $this->upload_key ); | ||||
| 			$this->set_dir(); | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
| 	public function onSetupBuilding(SetupBuildingEvent $event) { | ||||
| 		global $config; | ||||
| 		$this->set_dir(); | ||||
| 		 | ||||
| 		$cron_url = make_http(make_link("/cron_upload/" . $config->get_string('cron_uploader_key', 'invalid key' ))); | ||||
| 		$cron_cmd = "wget $cron_url"; | ||||
| 		$cron_url = make_http(make_link("/cron_upload/" . $this->upload_key)); | ||||
| 		$cron_cmd = "curl --silent $cron_url"; | ||||
| 		$documentation_link = make_http(make_link("cron_upload")); | ||||
| 		 | ||||
| 		$sb = new SetupBlock ( "Cron Uploader" ); | ||||
| @ -194,11 +202,11 @@ class CronUploader extends Extension { | ||||
| 			 | ||||
| 		// Make the directory if it doesn't exist yet
 | ||||
| 		if (!is_dir($dir . "/queue/"))  | ||||
| 			mkdir ( $dir . "/queue/", 0755, true ); | ||||
| 			mkdir ( $dir . "/queue/", 0775, true ); | ||||
| 		if (!is_dir($dir . "/uploaded/"))  | ||||
| 			mkdir ( $dir . "/uploaded/", 0755, true ); | ||||
| 			mkdir ( $dir . "/uploaded/", 0775, true ); | ||||
| 		if (!is_dir($dir . "/failed_to_upload/"))  | ||||
| 			mkdir ( $dir . "/failed_to_upload/", 0755, true ); | ||||
| 			mkdir ( $dir . "/failed_to_upload/", 0775, true ); | ||||
| 		 | ||||
| 		$this->root_dir = $dir; | ||||
| 		return $dir; | ||||
| @ -242,6 +250,7 @@ class CronUploader extends Extension { | ||||
| 		// Throw exception if there's nothing in the queue
 | ||||
| 		if (count($this->image_queue) == 0) { | ||||
| 			$this->add_upload_info("Your queue is empty so nothing could be uploaded."); | ||||
| 			$this->handle_log(); | ||||
| 			return false; | ||||
| 		} | ||||
| 		 | ||||
| @ -289,10 +298,9 @@ class CronUploader extends Extension { | ||||
| 		} | ||||
| 		 | ||||
| 		// move file to correct dir
 | ||||
| 		$newPath = $newDir . $filename; | ||||
| 		rename($path, $newPath); | ||||
| 		rename($path, $newDir.$filename); | ||||
| 		 | ||||
| 		$this->add_upload_info($info . "Image \"$filename\" moved from queue to \"$newPath\".");
 | ||||
| 		$this->add_upload_info($info . "Image \"$filename\" moved from queue to \"$newDir\".");
 | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
|  | ||||
| @ -420,8 +420,7 @@ class DanbooruApi extends Extension { | ||||
| 			// Code borrowed from /ext/user
 | ||||
| 			$name = $_REQUEST['login']; | ||||
| 			$pass = $_REQUEST['password']; | ||||
| 			$hash = md5( strtolower($name) . $pass ); | ||||
| 			$duser = User::by_name_and_hash($name, $hash); | ||||
| 			$duser = User::by_name_and_pass($name, $pass); | ||||
| 			if(!is_null($duser)) { | ||||
| 				$user = $duser; | ||||
| 			} else | ||||
|  | ||||
| @ -13,18 +13,32 @@ | ||||
|  *  add more emoticons by uploading images into that folder. | ||||
|  */ | ||||
| 
 | ||||
| /** | ||||
|  * Class Emoticons | ||||
|  */ | ||||
| class Emoticons extends FormatterExtension { | ||||
| 	/** | ||||
| 	 * @param string $text | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	public function format(/*string*/ $text) { | ||||
| 		$data_href = get_base_href(); | ||||
| 		$text = preg_replace("/:([a-z]*?):/s", "<img src='$data_href/ext/emoticons/default/\\1.gif'>", $text); | ||||
| 		return $text; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $text | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	public function strip(/*string*/ $text) { | ||||
| 		return $text; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Class EmoticonList | ||||
|  */ | ||||
| class EmoticonList extends Extension { | ||||
| 	public function onPageRequest(PageRequestEvent $event) { | ||||
| 		if($event->page_matches("emote/list")) { | ||||
|  | ||||
| @ -1,5 +1,8 @@ | ||||
| <?php | ||||
| class EmoticonListTheme extends Themelet { | ||||
| 	/** | ||||
| 	 * @param array $list | ||||
| 	 */ | ||||
| 	public function display_emotes(/*array*/ $list) { | ||||
| 		global $page; | ||||
| 		$data_href = get_base_href(); | ||||
|  | ||||
| @ -81,6 +81,10 @@ class ExtensionInfo { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $fname | ||||
| 	 * @return bool|null | ||||
| 	 */ | ||||
| 	private function is_enabled(/*string*/ $fname) { | ||||
| 		$core = explode(",", CORE_EXTS); | ||||
| 		$extra = explode(",", EXTRA_EXTS); | ||||
| @ -150,7 +154,10 @@ class ExtManager extends Extension { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param bool $all | ||||
| 	 * @return array | ||||
| 	 */ | ||||
| 	private function get_extensions(/*bool*/ $all) { | ||||
| 		$extensions = array(); | ||||
| 		if($all) { | ||||
|  | ||||
| @ -14,8 +14,18 @@ | ||||
|  */ | ||||
| 
 | ||||
| class FavoriteSetEvent extends Event { | ||||
| 	var $image_id, $user, $do_set; | ||||
| 	/** @var int */ | ||||
| 	public $image_id; | ||||
| 	/** @var \User */ | ||||
| 	public $user; | ||||
| 	/** @var bool */ | ||||
| 	public $do_set; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param int $image_id | ||||
| 	 * @param User $user | ||||
| 	 * @param bool $do_set | ||||
| 	 */ | ||||
| 	public function __construct(/*int*/ $image_id, User $user, /*boolean*/ $do_set) { | ||||
| 		assert(is_numeric($image_id)); | ||||
| 		assert(is_bool($do_set)); | ||||
| @ -172,6 +182,11 @@ class Favorites extends Extension { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param int $image_id | ||||
| 	 * @param int $user_id | ||||
| 	 * @param bool $do_set | ||||
| 	 */ | ||||
| 	private function add_vote(/*int*/ $image_id, /*int*/ $user_id, /*bool*/ $do_set) { | ||||
| 		global $database; | ||||
| 		if ($do_set) { | ||||
| @ -188,6 +203,10 @@ class Favorites extends Extension { | ||||
| 			array("image_id"=>$image_id, "user_id"=>$user_id)); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param Image $image | ||||
| 	 * @return array | ||||
| 	 */ | ||||
| 	private function list_persons_who_have_favorited(Image $image) { | ||||
| 		global $database; | ||||
| 
 | ||||
|  | ||||
| @ -60,13 +60,13 @@ class Featured extends Extension { | ||||
| 		global $config, $database, $page, $user; | ||||
| 		$fid = $config->get_int("featured_id"); | ||||
| 		if($fid > 0) { | ||||
| 			$image = $database->cache->get("featured_image_object-$fid"); | ||||
| 			$image = $database->cache->get("featured_image_object:$fid"); | ||||
| 			if($image === false) { | ||||
| 				$image = Image::by_id($fid); | ||||
| 				if($image) { // make sure the object is fully populated before saving
 | ||||
| 					$image->get_tag_array(); | ||||
| 				} | ||||
| 				$database->cache->set("featured_image_object-$fid", $image, 600); | ||||
| 				$database->cache->set("featured_image_object:$fid", $image, 600); | ||||
| 			} | ||||
| 			if(!is_null($image)) { | ||||
| 				if(class_exists("Ratings")) { | ||||
|  | ||||
| @ -1,26 +1,37 @@ | ||||
| <?php | ||||
| 
 | ||||
| class FeaturedTheme extends Themelet { | ||||
| 	/* | ||||
| 	 * Show $text on the $page | ||||
| 	/** | ||||
| 	 * Show $text on the $page. | ||||
| 	 * | ||||
| 	 * @param Page $page | ||||
| 	 * @param Image $image | ||||
| 	 */ | ||||
| 	public function display_featured(Page $page, Image $image) { | ||||
| 		$page->add_block(new Block("Featured Image", $this->build_featured_html($image), "left", 3)); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param int $image_id | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	public function get_buttons_html(/*int*/ $image_id) { | ||||
| 		global $user; | ||||
| 		return " | ||||
| 			".make_form(make_link("featured_image/set"))." | ||||
| 			".$user->get_auth_html()." | ||||
| 			<input type='hidden' name='image_id' value='$image_id'> | ||||
| 			<input type='hidden' name='image_id' value='{$image_id}'> | ||||
| 			<input type='submit' value='Feature This'> | ||||
| 			</form> | ||||
| 		";
 | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param Image $image | ||||
| 	 * @param null|string $query | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	public function build_featured_html(Image $image, $query=null) { | ||||
| 		global $config; | ||||
| 		$i_id = int_escape($image->id); | ||||
| 		$h_view_link = make_link("post/view/$i_id", $query); | ||||
| 		$h_thumb_link = $image->get_thumb_link(); | ||||
| @ -29,7 +40,7 @@ class FeaturedTheme extends Themelet { | ||||
| 
 | ||||
| 		return " | ||||
| 			<a href='$h_view_link'> | ||||
| 				<img id='thumb_$i_id' title='$h_tip' alt='$h_tip' class='highlighted' style='height: {$tsize[1]}px; width: {$tsize[0]}px;' src='$h_thumb_link'> | ||||
| 				<img id='thumb_{$i_id}' title='{$h_tip}' alt='{$h_tip}' class='highlighted' style='height: {$tsize[1]}px; width: {$tsize[0]}px;' src='{$h_thumb_link}'> | ||||
| 			</a> | ||||
| 		";
 | ||||
| 	} | ||||
|  | ||||
| @ -39,7 +39,10 @@ class ArchiveFileHandler extends Extension { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param $ext | ||||
| 	 * @return bool | ||||
| 	 */ | ||||
| 	private function supported_ext($ext) { | ||||
| 		$exts = array("zip"); | ||||
| 		return in_array(strtolower($ext), $exts); | ||||
|  | ||||
| @ -7,15 +7,29 @@ | ||||
|  */ | ||||
| 
 | ||||
| class FlashFileHandler extends DataHandlerExtension { | ||||
| 	/** | ||||
| 	 * @param string $hash | ||||
| 	 * @return bool | ||||
| 	 */ | ||||
| 	protected function create_thumb($hash) { | ||||
| 		copy("ext/handle_flash/thumb.jpg", warehouse_path("thumbs", $hash)); | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $ext | ||||
| 	 * @return bool | ||||
| 	 */ | ||||
| 	protected function supported_ext($ext) { | ||||
| 		$exts = array("swf"); | ||||
| 		return in_array(strtolower($ext), $exts); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $filename | ||||
| 	 * @param array $metadata | ||||
| 	 * @return Image|null | ||||
| 	 */ | ||||
| 	protected function create_image_from_data(/*string*/ $filename, /*array*/ $metadata) { | ||||
| 		$image = new Image(); | ||||
| 
 | ||||
| @ -35,6 +49,10 @@ class FlashFileHandler extends DataHandlerExtension { | ||||
| 		return $image; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param $file | ||||
| 	 * @return bool | ||||
| 	 */ | ||||
| 	protected function check_contents(/*string*/ $file) { | ||||
| 		if (!file_exists($file)) return false; | ||||
| 
 | ||||
|  | ||||
| @ -49,12 +49,20 @@ class IcoFileHandler extends Extension { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param $ext | ||||
| 	 * @return bool | ||||
| 	 */ | ||||
| 	private function supported_ext($ext) { | ||||
| 		$exts = array("ico", "ani", "cur"); | ||||
| 		return in_array(strtolower($ext), $exts); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param $filename | ||||
| 	 * @param $metadata | ||||
| 	 * @return Image | ||||
| 	 */ | ||||
| 	private function create_image_from_data($filename, $metadata) { | ||||
| 		$image = new Image(); | ||||
| 
 | ||||
| @ -77,6 +85,10 @@ class IcoFileHandler extends Extension { | ||||
| 		return $image; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param $file | ||||
| 	 * @return bool | ||||
| 	 */ | ||||
| 	private function check_contents($file) { | ||||
| 		if(!file_exists($file)) return false; | ||||
| 		$fp = fopen($file, "r"); | ||||
| @ -85,6 +97,10 @@ class IcoFileHandler extends Extension { | ||||
| 		return ($header['null'] == 0 && ($header['type'] == 0 || $header['type'] == 1)); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param $hash | ||||
| 	 * @return bool | ||||
| 	 */ | ||||
| 	private function create_thumb($hash) { | ||||
| 		global $config; | ||||
| 
 | ||||
|  | ||||
| @ -6,15 +6,29 @@ | ||||
|  */ | ||||
| 
 | ||||
| class MP3FileHandler extends DataHandlerExtension { | ||||
| 	/** | ||||
| 	 * @param string $hash | ||||
| 	 * @return bool | ||||
| 	 */ | ||||
| 	protected function create_thumb($hash) { | ||||
| 		copy("ext/handle_mp3/thumb.jpg", warehouse_path("thumbs", $hash)); | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $ext | ||||
| 	 * @return bool | ||||
| 	 */ | ||||
| 	protected function supported_ext($ext) { | ||||
| 		$exts = array("mp3"); | ||||
| 		return in_array(strtolower($ext), $exts); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $filename | ||||
| 	 * @param array $metadata | ||||
| 	 * @return Image|null | ||||
| 	 */ | ||||
| 	protected function create_image_from_data($filename, $metadata) { | ||||
| 		global $config; | ||||
| 
 | ||||
| @ -47,6 +61,10 @@ class MP3FileHandler extends DataHandlerExtension { | ||||
| 		return $image; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param $file | ||||
| 	 * @return bool | ||||
| 	 */ | ||||
| 	protected function check_contents($file) { | ||||
| 		if (file_exists($file)) { | ||||
| 			require_once('lib/getid3/getid3/getid3.php'); | ||||
|  | ||||
| @ -7,12 +7,21 @@ | ||||
|  */ | ||||
| 
 | ||||
| class PixelFileHandler extends DataHandlerExtension { | ||||
| 	/** | ||||
| 	 * @param string $ext | ||||
| 	 * @return bool | ||||
| 	 */ | ||||
| 	protected function supported_ext($ext) { | ||||
| 		$exts = array("jpg", "jpeg", "gif", "png"); | ||||
| 		$ext = (($pos = strpos($ext,'?')) !== false) ? substr($ext,0,$pos) : $ext; | ||||
| 		return in_array(strtolower($ext), $exts); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $filename | ||||
| 	 * @param array $metadata | ||||
| 	 * @return Image|null | ||||
| 	 */ | ||||
| 	protected function create_image_from_data(/*string*/ $filename, /*array*/ $metadata) { | ||||
| 		$image = new Image(); | ||||
| 
 | ||||
| @ -32,6 +41,10 @@ class PixelFileHandler extends DataHandlerExtension { | ||||
| 		return $image; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $file | ||||
| 	 * @return bool | ||||
| 	 */ | ||||
| 	protected function check_contents(/*string*/ $file) { | ||||
| 		$valid = Array(IMAGETYPE_PNG, IMAGETYPE_GIF, IMAGETYPE_JPEG); | ||||
| 		if(!file_exists($file)) return false; | ||||
| @ -41,6 +54,10 @@ class PixelFileHandler extends DataHandlerExtension { | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $hash | ||||
| 	 * @return bool | ||||
| 	 */ | ||||
| 	protected function create_thumb(/*string*/ $hash) { | ||||
| 		$outname = warehouse_path("thumbs", $hash); | ||||
| 		if(file_exists($outname)) { | ||||
| @ -49,6 +66,10 @@ class PixelFileHandler extends DataHandlerExtension { | ||||
| 		return $this->create_thumb_force($hash); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param $hash | ||||
| 	 * @return bool | ||||
| 	 */ | ||||
| 	protected function create_thumb_force(/*string*/ $hash) { | ||||
| 		global $config; | ||||
| 
 | ||||
| @ -70,6 +91,9 @@ class PixelFileHandler extends DataHandlerExtension { | ||||
| 		return $ok; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param ImageAdminBlockBuildingEvent $event | ||||
| 	 */ | ||||
| 	public function onImageAdminBlockBuilding(ImageAdminBlockBuildingEvent $event) { | ||||
| 		$event->add_part(" | ||||
| 			<form> | ||||
| @ -83,14 +107,22 @@ class PixelFileHandler extends DataHandlerExtension { | ||||
| 		", 20);
 | ||||
| 
 | ||||
| 		$u_ilink = $event->image->get_image_link(); | ||||
| 		$nu_enabled = (strpos($u_ilink, '?') !== false ? "<input type='hidden' name='q' value='image/{$event->image->id}.{$event->image->ext}' />" : ""); | ||||
| 		$event->add_part(" | ||||
| 			<form action='{$u_ilink}'> | ||||
| 				$nu_enabled | ||||
| 				<input type='submit' value='Image Only'> | ||||
| 			</form> | ||||
| 		", 21);
 | ||||
| 	} | ||||
| 
 | ||||
| // IM thumber {{{
 | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $inname | ||||
| 	 * @param string $outname | ||||
| 	 * @return bool | ||||
| 	 */ | ||||
| 	private function make_thumb_convert(/*string*/ $inname, /*string*/ $outname) { | ||||
| 		global $config; | ||||
| 
 | ||||
| @ -124,6 +156,11 @@ class PixelFileHandler extends DataHandlerExtension { | ||||
| 	} | ||||
| // }}}
 | ||||
| // epeg thumber {{{
 | ||||
| 	/** | ||||
| 	 * @param string $inname | ||||
| 	 * @param string $outname | ||||
| 	 * @return bool | ||||
| 	 */ | ||||
| 	private function make_thumb_epeg(/*string*/ $inname, /*string*/ $outname) { | ||||
| 		global $config; | ||||
| 		$w = $config->get_int("thumb_width"); | ||||
| @ -132,6 +169,11 @@ class PixelFileHandler extends DataHandlerExtension { | ||||
| 	} | ||||
| 	// }}}
 | ||||
| // GD thumber {{{
 | ||||
| 	/** | ||||
| 	 * @param string $inname | ||||
| 	 * @param string $outname | ||||
| 	 * @return bool | ||||
| 	 */ | ||||
| 	private function make_thumb_gd(/*string*/ $inname, /*string*/ $outname) { | ||||
| 		global $config; | ||||
| 		$thumb = $this->get_thumb($inname); | ||||
| @ -140,6 +182,10 @@ class PixelFileHandler extends DataHandlerExtension { | ||||
| 		return $ok; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $tmpname | ||||
| 	 * @return resource | ||||
| 	 */ | ||||
| 	private function get_thumb(/*string*/ $tmpname) { | ||||
| 		global $config; | ||||
| 
 | ||||
|  | ||||
| @ -51,11 +51,20 @@ class SVGFileHandler extends Extension { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param $ext | ||||
| 	 * @return bool | ||||
| 	 */ | ||||
| 	private function supported_ext($ext) { | ||||
| 		$exts = array("svg"); | ||||
| 		return in_array(strtolower($ext), $exts); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param $filename | ||||
| 	 * @param $metadata | ||||
| 	 * @return Image | ||||
| 	 */ | ||||
| 	private function create_image_from_data($filename, $metadata) { | ||||
| 		global $config; | ||||
| 
 | ||||
| @ -75,21 +84,30 @@ class SVGFileHandler extends Extension { | ||||
| 		return $image; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param $file | ||||
| 	 * @return bool | ||||
| 	 */ | ||||
| 	private function check_contents($file) { | ||||
| 		if(!file_exists($file)) return false; | ||||
| 
 | ||||
| 		$msp = new MiniSVGParser($file); | ||||
| 		return $msp->valid; | ||||
| 		return bool_escape($msp->valid); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| class MiniSVGParser { | ||||
| 	var $valid=false, $width=0, $height=0; | ||||
| 	/** @var bool */ | ||||
| 	public $valid=false; | ||||
| 	/** @var int */ | ||||
| 	public $width=0; | ||||
| 	/** @var int */ | ||||
| 	public $height=0; | ||||
| 
 | ||||
| 	function __construct($file) { | ||||
| 		$xml_parser = xml_parser_create(); | ||||
| 		xml_set_element_handler($xml_parser, array($this, "startElement"), array($this, "endElement")); | ||||
| 		$this->valid = xml_parse($xml_parser, file_get_contents($file), true); | ||||
| 		$this->valid = bool_escape(xml_parse($xml_parser, file_get_contents($file), true)); | ||||
| 		xml_parser_free($xml_parser); | ||||
| 	} | ||||
| 
 | ||||
|  | ||||
| @ -2,6 +2,7 @@ | ||||
| /* | ||||
|  * Name: Handle Video | ||||
|  * Author: velocity37 <velocity37@gmail.com> | ||||
|  * Modified By: Shish <webmaster@shishnet.org>, jgen <jeffgenovy@gmail.com> | ||||
|  * License: GPLv2 | ||||
|  * Description: Handle FLV, MP4, OGV and WEBM video files. | ||||
|  * Documentation: | ||||
| @ -17,17 +18,88 @@ | ||||
|  */ | ||||
| 
 | ||||
| class VideoFileHandler extends DataHandlerExtension { | ||||
| 	protected function create_thumb($hash) { | ||||
| 		copy("ext/handle_video/thumb.jpg", warehouse_path("thumbs", $hash)); | ||||
| 	public function onInitExt(InitExtEvent $event) { | ||||
| 		global $config; | ||||
| 		$config->set_default_string('video_thumb_engine', 'static'); | ||||
| 		$config->set_default_string('thumb_ffmpeg_path', ''); | ||||
| 	} | ||||
| 
 | ||||
| 	public function onSetupBuilding(SetupBuildingEvent $event) { | ||||
| 		global $config; | ||||
| 
 | ||||
| 		$thumbers = array(); | ||||
| 		$thumbers['None'] = "static"; | ||||
| 		$thumbers['ffmpeg'] = "ffmpeg"; | ||||
| 
 | ||||
| 		$sb = new SetupBlock("Video Thumbnail Options"); | ||||
| 
 | ||||
| 		$sb->add_choice_option("video_thumb_engine", $thumbers, "Engine: "); | ||||
| 
 | ||||
| 		//if($config->get_string("video_thumb_engine") == "ffmpeg") {
 | ||||
| 			$sb->add_label("<br>Path to ffmpeg: "); | ||||
| 			$sb->add_text_option("thumb_ffmpeg_path"); | ||||
| 		//}
 | ||||
| 		$event->panel->add_block($sb); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $hash | ||||
| 	 * @return bool | ||||
| 	 */ | ||||
| 	protected function create_thumb($hash) { | ||||
| 		global $config; | ||||
| 
 | ||||
| 		// this is never used...
 | ||||
| 		//$q = $config->get_int("thumb_quality");
 | ||||
| 
 | ||||
| 		$ok = false; | ||||
| 
 | ||||
| 		switch($config->get_string("video_thumb_engine")) | ||||
| 		{ | ||||
| 			default: | ||||
| 			case 'static': | ||||
| 				$outname = warehouse_path("thumbs", $hash); | ||||
| 				copy("ext/handle_video/thumb.jpg", $outname); | ||||
| 				$ok = true; | ||||
| 				break; | ||||
| 			case 'ffmpeg': | ||||
| 				$ffmpeg = escapeshellarg($config->get_string("thumb_ffmpeg_path")); | ||||
| 
 | ||||
| 				$w = (int)$config->get_int("thumb_width"); | ||||
| 				$h = (int)$config->get_int("thumb_height"); | ||||
| 				$inname  = escapeshellarg(warehouse_path("images", $hash)); | ||||
| 				$outname = escapeshellarg(warehouse_path("thumbs", $hash)); | ||||
| 
 | ||||
| 				$cmd = escapeshellcmd("{$ffmpeg} -i {$inname} -vf scale='if(gt(a,{$w}/{$h}),{$w},-1)':'if(gt(a,{$w}/{$h}),-1,{$h})' -ss 00:00:00.0 -f image2 -vframes 1 {$outname}"); | ||||
| 
 | ||||
| 				exec($cmd, $output, $ret); | ||||
| 
 | ||||
| 				// TODO: We should really check the result of the exec to see if it really succeeded.
 | ||||
| 				$ok = true; | ||||
| 
 | ||||
| 				log_debug('handle_video', "Generating thumbnail with command `$cmd`, returns $ret"); | ||||
| 				break; | ||||
| 		} | ||||
| 
 | ||||
| 		return $ok; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $ext | ||||
| 	 * @return bool | ||||
| 	 */ | ||||
| 	protected function supported_ext($ext) { | ||||
| 		$exts = array("flv", "mp4", "m4v", "ogv", "webm"); | ||||
| 		return in_array(strtolower($ext), $exts); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $filename | ||||
| 	 * @param array $metadata | ||||
| 	 * @return Image|null | ||||
| 	 */ | ||||
| 	protected function create_image_from_data($filename, $metadata) { | ||||
| 		global $config; | ||||
| 		//global $config;
 | ||||
| 
 | ||||
| 		$image = new Image(); | ||||
| 
 | ||||
| @ -67,12 +139,21 @@ class VideoFileHandler extends DataHandlerExtension { | ||||
| 		return $image; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param $file | ||||
| 	 * @return bool | ||||
| 	 */ | ||||
| 	protected function check_contents($file) { | ||||
| 		if (file_exists($file)) { | ||||
| 			require_once('lib/getid3/getid3/getid3.php'); | ||||
| 			$getID3 = new getID3; | ||||
| 			$ThisFileInfo = $getID3->analyze($file); | ||||
| 			if (isset($ThisFileInfo['mime_type']) && ($ThisFileInfo['mime_type'] == "video/webm" || $ThisFileInfo['mime_type'] == "video/quicktime" || $ThisFileInfo['mime_type'] == "application/ogg" || $ThisFileInfo['mime_type'] == 'video/x-flv')) { | ||||
| 			if (isset($ThisFileInfo['mime_type']) && ( | ||||
| 					$ThisFileInfo['mime_type'] == "video/webm"      || | ||||
| 					$ThisFileInfo['mime_type'] == "video/quicktime" || | ||||
| 					$ThisFileInfo['mime_type'] == "application/ogg" || | ||||
| 					$ThisFileInfo['mime_type'] == 'video/x-flv') | ||||
| 			) { | ||||
| 				return TRUE; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| @ -7,27 +7,38 @@ class VideoFileHandlerTheme extends Themelet { | ||||
| 		$ext = strtolower($image->get_ext()); | ||||
| 		 | ||||
| 		if ($ext == "mp4") { | ||||
| 			$html = "Video not playing? <a href='" . $image->parse_link_template(make_link('image/$id/$id%20-%20$tags.$ext')) . "'>Click here</a> to download the file.<br><script language='JavaScript' type='text/javascript'>
 | ||||
| 			$html = "Video not playing? <a href='" . $image->parse_link_template(make_link('image/$id/$id%20-%20$tags.$ext')) . "'>Click here</a> to download the file.<br/>
 | ||||
| 			<script language='JavaScript' type='text/javascript'> | ||||
| if( navigator.userAgent.match(/Firefox/i) || | ||||
| 	navigator.userAgent.match(/Opera/i) || | ||||
| 	(navigator.userAgent.match(/MSIE/i) && parseFloat(navigator.appVersion.split('MSIE')[1]) < 9)){ | ||||
| 		document.write(\"<object data='$data_href/lib/Jaris/bin/JarisFLVPlayer.swf' id='VideoPlayer' type='application/x-shockwave-flash' height='" . strval($image->height + 1). "px' width='" . strval($image->width) . "px'><param value='#000000' name='bgcolor'><param name='allowFullScreen' value='true'><param value='high' name='quality'><param value='opaque' name='wmode'><param value='source=$ilink&type=video&streamtype=file&controltype=0' name='flashvars'></object>\");
 | ||||
| 		document.write(\"<object data='{$data_href}/lib/Jaris/bin/JarisFLVPlayer.swf' id='VideoPlayer' type='application/x-shockwave-flash' height='" . strval($image->height + 1). "px' width='" . strval($image->width) . "px'><param value='#000000' name='bgcolor'><param name='allowFullScreen' value='true'><param value='high' name='quality'><param value='opaque' name='wmode'><param value='source=$ilink&type=video&streamtype=file&controltype=0' name='flashvars'></object>\");
 | ||||
| } | ||||
| else {	 | ||||
| 		document.write(\"<video controls='controls' autoplay='autoplay'>\");
 | ||||
| 		document.write(\"<video controls autoplay loop'>\");
 | ||||
| 		document.write(\"<source src='" . make_link("/image/" . $image->id) . "' type='video/mp4' />\");
 | ||||
| 		document.write(\"<object data='$data_href/lib/Jaris/bin/JarisFLVPlayer.swf' id='VideoPlayer' type='application/x-shockwave-flash' height='" . strval($image->height + 1). "px' width='" . strval($image->width) . "px'><param value='#000000' name='bgcolor'><param name='allowFullScreen' value='true'><param value='high' name='quality'><param value='opaque' name='wmode'><param value='source=$ilink&type=video&streamtype=file&controltype=0' name='flashvars'></object>\");
 | ||||
| 		document.write(\"<object data='{$data_href}/lib/Jaris/bin/JarisFLVPlayer.swf' id='VideoPlayer' type='application/x-shockwave-flash' height='" . strval($image->height + 1). "px' width='" . strval($image->width) . "px'><param value='#000000' name='bgcolor'><param name='allowFullScreen' value='true'><param value='high' name='quality'><param value='opaque' name='wmode'><param value='source=$ilink&type=video&streamtype=file&controltype=0' name='flashvars'></object>\");
 | ||||
| } | ||||
| </script> | ||||
| <noscript>Javascript appears to be disabled. Please enable it and try again.</noscript>";
 | ||||
| 		} elseif ($ext == "flv") { | ||||
| 			$html = "Video not playing? <a href='" . $image->parse_link_template(make_link('image/$id/$id%20-%20$tags.$ext')) . "'>Click here</a> to download the file.<br><object data='$data_href/lib/Jaris/bin/JarisFLVPlayer.swf' id='VideoPlayer' type='application/x-shockwave-flash' height='" . strval($image->height + 1). "px' width='" . strval($image->width) . "px'><param value='#000000' name='bgcolor'><param name='allowFullScreen' value='true'><param value='high' name='quality'><param value='opaque' name='wmode'><param value='source=$ilink&type=video&streamtype=file&controltype=0' name='flashvars'></object>"; | ||||
| 			$html = "Video not playing? <a href='" . $image->parse_link_template(make_link('image/$id/$id%20-%20$tags.$ext')) . "'>Click here</a> to download the file.<br/>
 | ||||
| 			<object data='{$data_href}/lib/Jaris/bin/JarisFLVPlayer.swf' id='VideoPlayer' type='application/x-shockwave-flash' height='" . strval($image->height + 1). "px' width='" . strval($image->width) . "px'> | ||||
| 			<param value='#000000' name='bgcolor'> | ||||
| 			<param name='allowFullScreen' value='true'> | ||||
| 			<param value='high' name='quality'> | ||||
| 			<param value='opaque' name='wmode'> | ||||
| 			<param value='source={$ilink}&type=video&streamtype=file&controltype=0' name='flashvars'> | ||||
| 			</object>";
 | ||||
| 		} elseif ($ext == "ogv") { | ||||
| 			$html = "Video not playing? <a href='" . $image->parse_link_template(make_link('image/$id/$id%20-%20$tags.$ext')) . "'>Click here</a> to download the file.<br><video controls='controls' autoplay='autoplay'>
 | ||||
| 			$html = "Video not playing? <a href='" . $image->parse_link_template(make_link('image/$id/$id%20-%20$tags.$ext')) . "'>Click here</a> to download the file.<br/>
 | ||||
| 			<video controls autoplay loop> | ||||
| 			<source src='" . make_link("/image/" . $image->id) . "' type='video/ogg' /> | ||||
| 			</video>";
 | ||||
| 		} elseif ($ext == "webm") { | ||||
| 			$html = "Video not playing? <a href='" . $image->parse_link_template(make_link('image/$id/$id%20-%20$tags.$ext')) . "'>Click here</a> to download the file.<br><video controls='controls' autoplay='autoplay'>
 | ||||
| 			$ie_only = "<!--[if IE]><p>To view webm files with IE, please <a href='http://tools.google.com/dlpage/webmmf/' target='_blank'>download this plugin</a>.</p><![endif]-->"; | ||||
| 			$html = $ie_only ."Video not playing? <a href='" . $image->parse_link_template(make_link('image/$id/$id%20-%20$tags.$ext')) . "'>Click here</a> to download the file.<br/>
 | ||||
| 			<video controls autoplay loop> | ||||
| 			<source src='" . make_link("/image/" . $image->id) . "' type='video/webm' /> | ||||
| 			</video>";
 | ||||
| 		} | ||||
|  | ||||
| @ -12,15 +12,17 @@ | ||||
|  * An image is being added to the database. | ||||
|  */ | ||||
| class ImageAdditionEvent extends Event { | ||||
| 	var $user, $image; | ||||
| 	var $user; | ||||
| 	/** @var \Image */ | ||||
| 	public $image; | ||||
| 	 | ||||
| 	/** | ||||
| 	 * Inserts a new image into the database with its associated | ||||
| 	 * information. Also calls TagSetEvent to set the tags for | ||||
| 	 * this new image. | ||||
| 	 * | ||||
| 	 * @sa TagSetEvent | ||||
| 	 * @param $image Image	The new image to add. | ||||
| 	 * @see TagSetEvent | ||||
| 	 * @param Image $image The new image to add. | ||||
| 	 */ | ||||
| 	public function __construct(Image $image) { | ||||
| 		$this->image = $image; | ||||
| @ -39,14 +41,16 @@ class ImageAdditionException extends SCoreException { | ||||
|  * An image is being deleted. | ||||
|  */ | ||||
| class ImageDeletionEvent extends Event { | ||||
| 	var $image; | ||||
| 	/** @var \Image */ | ||||
| 	public $image; | ||||
| 	 | ||||
| 	/** | ||||
| 	 * Deletes an image. | ||||
| 	 * | ||||
| 	 * Used by things like tags and comments handlers to | ||||
| 	 * clean out related rows in their tables. | ||||
| 	 * | ||||
| 	 * @param $image Image	The image being deleted | ||||
| 	 * @param Image $image The image being deleted. | ||||
| 	*/ | ||||
| 	public function __construct(Image $image) { | ||||
| 		$this->image = $image; | ||||
| @ -57,18 +61,20 @@ class ImageDeletionEvent extends Event { | ||||
|  * An image is being replaced. | ||||
|  */ | ||||
| class ImageReplaceEvent extends Event { | ||||
| 	var $id, $image; | ||||
| 	/** @var int */ | ||||
| 	public $id; | ||||
| 	/** @var \Image */ | ||||
| 	public $image; | ||||
| 	 | ||||
| 	/** | ||||
| 	 * Replaces an image. | ||||
| 	 * | ||||
| 	 * Updates an existing ID in the database to use a new image | ||||
| 	 * file, leaving the tags and such unchanged. Also removes  | ||||
| 	 * the old image file and thumbnail from the disk. | ||||
| 	 * | ||||
| 	 * @param $id | ||||
| 	 *   The ID of the image to replace | ||||
| 	 * @param $image | ||||
| 	 *   The image object of the new image to use | ||||
| 	 * @param int $id The ID of the image to replace. | ||||
| 	 * @param Image $image The image object of the new image to use. | ||||
| 	 */ | ||||
| 	public function __construct(/*int*/ $id, Image $image) { | ||||
| 		$this->id = $id; | ||||
| @ -77,8 +83,12 @@ class ImageReplaceEvent extends Event { | ||||
| } | ||||
| 
 | ||||
| class ImageReplaceException extends SCoreException { | ||||
| 	var $error; | ||||
| 	/** @var string */ | ||||
| 	public $error; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $error | ||||
| 	 */ | ||||
| 	public function __construct(/*string*/ $error) { | ||||
| 		$this->error = $error; | ||||
| 	} | ||||
| @ -88,14 +98,19 @@ class ImageReplaceException extends SCoreException { | ||||
|  * Request a thumbnail be made for an image object. | ||||
|  */ | ||||
| class ThumbnailGenerationEvent extends Event { | ||||
| 	var $hash, $type, $force; | ||||
| 	/** @var string */ | ||||
| 	public $hash; | ||||
| 	/** @var string */ | ||||
| 	public $type; | ||||
| 	/** @var bool */ | ||||
| 	public $force; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Request a thumbnail be made for an image object | ||||
| 	 * | ||||
| 	 * @param $hash	string The unique hash of the image | ||||
| 	 * @param $type	string The type of the image | ||||
| 	 * @param $force boolean Regenerate the thumbnail even if one already exists | ||||
| 	 * @param string $hash The unique hash of the image | ||||
| 	 * @param string $type The type of the image | ||||
| 	 * @param bool $force Regenerate the thumbnail even if one already exists | ||||
| 	 */ | ||||
| 	public function __construct($hash, $type, $force=false) { | ||||
| 		$this->hash = $hash; | ||||
| @ -112,14 +127,27 @@ class ThumbnailGenerationEvent extends Event { | ||||
|  *   $image    -- the image who's link is being parsed | ||||
|  */ | ||||
| class ParseLinkTemplateEvent extends Event { | ||||
| 	var $link, $original, $image; | ||||
| 	/** @var string */ | ||||
| 	public $link; | ||||
| 	/** @var string */ | ||||
| 	public $original; | ||||
| 	/** @var \Image */ | ||||
| 	public $image; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $link The formatted link | ||||
| 	 * @param Image $image The image who's link is being parsed | ||||
| 	 */ | ||||
| 	public function __construct($link, Image $image) { | ||||
| 		$this->link = $link; | ||||
| 		$this->original = $link; | ||||
| 		$this->image = $image; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $needle | ||||
| 	 * @param string $replace | ||||
| 	 */ | ||||
| 	public function replace($needle, $replace) { | ||||
| 		$this->link = str_replace($needle, $replace, $this->link); | ||||
| 	} | ||||
| @ -189,8 +217,7 @@ class ImageIO extends Extension { | ||||
| 	} | ||||
| 
 | ||||
| 	public function onImageAdminBlockBuilding(ImageAdminBlockBuildingEvent $event) { | ||||
| 		global $user; | ||||
| 		global $config; | ||||
| 		global $user, $config; | ||||
| 		 | ||||
| 		if($user->can("delete_image")) { | ||||
| 			$event->add_part($this->theme->get_deleter_html($event->image->id)); | ||||
| @ -277,6 +304,11 @@ class ImageIO extends Extension { | ||||
| 
 | ||||
| 
 | ||||
| // add image {{{
 | ||||
| 	/** | ||||
| 	 * @param Image $image | ||||
| 	 * @return null | ||||
| 	 * @throws ImageAdditionException | ||||
| 	 */ | ||||
| 	private function add_image(Image $image) { | ||||
| 		global $page, $user, $database, $config; | ||||
| 
 | ||||
| @ -346,6 +378,10 @@ class ImageIO extends Extension { | ||||
| // }}}  end add
 | ||||
| 
 | ||||
| // fetch image {{{
 | ||||
| 	/** | ||||
| 	 * @param int $image_id | ||||
| 	 * @param string $type | ||||
| 	 */ | ||||
| 	private function send_file($image_id, $type) { | ||||
| 		global $config; | ||||
| 		global $database; | ||||
| @ -398,6 +434,11 @@ class ImageIO extends Extension { | ||||
| // }}} end fetch
 | ||||
| 
 | ||||
| // replace image {{{
 | ||||
| 	/** | ||||
| 	 * @param int $id | ||||
| 	 * @param Image $image | ||||
| 	 * @throws ImageReplaceException | ||||
| 	 */ | ||||
| 	private function replace_image($id, $image) { | ||||
| 		global $database; | ||||
| 
 | ||||
|  | ||||
| @ -159,23 +159,39 @@ | ||||
|  * Signal that a search term needs parsing | ||||
|  */ | ||||
| class SearchTermParseEvent extends Event { | ||||
| 	var $term = null; | ||||
| 	var $context = null; | ||||
| 	var $querylets = array(); | ||||
| 	/** @var null|string  */ | ||||
| 	public $term = null; | ||||
| 	/** @var null|array */ | ||||
| 	public $context = null; | ||||
| 	/** @var \Querylet[] */ | ||||
| 	public $querylets = array(); | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string|null $term | ||||
| 	 * @param array|null $context | ||||
| 	 */ | ||||
| 	public function __construct($term, $context) { | ||||
| 		$this->term = $term; | ||||
| 		$this->context = $context; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @return bool | ||||
| 	 */ | ||||
| 	public function is_querylet_set() { | ||||
| 		return (count($this->querylets) > 0); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @return \Querylet[] | ||||
| 	 */ | ||||
| 	public function get_querylets() { | ||||
| 		return $this->querylets; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param \Querylet $q | ||||
| 	 */ | ||||
| 	public function add_querylet($q) { | ||||
| 		$this->querylets[] = $q; | ||||
| 	} | ||||
| @ -185,13 +201,23 @@ class SearchTermParseException extends SCoreException { | ||||
| } | ||||
| 
 | ||||
| class PostListBuildingEvent extends Event { | ||||
| 	var $search_terms = null; | ||||
| 	var $parts = array(); | ||||
| 	/** @var null|array */ | ||||
| 	public $search_terms = null; | ||||
| 
 | ||||
| 	/** @var array */ | ||||
| 	public $parts = array(); | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param array|null $search | ||||
| 	 */ | ||||
| 	public function __construct($search) { | ||||
| 		$this->search_terms = $search; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $html | ||||
| 	 * @param int $position | ||||
| 	 */ | ||||
| 	public function add_control(/*string*/ $html, /*int*/ $position=50) { | ||||
| 		while(isset($this->parts[$position])) $position++; | ||||
| 		$this->parts[$position] = $html; | ||||
| @ -234,10 +260,10 @@ class Index extends Extension { | ||||
| 				#log_debug("index", "Search for ".implode(" ", $search_terms), false, array("terms"=>$search_terms));
 | ||||
| 				$total_pages = Image::count_pages($search_terms); | ||||
| 				if(SPEED_HAX && $count_search_terms === 0 && ($page_number < 10)) { // extra caching for the first few post/list pages
 | ||||
| 					$images = $database->cache->get("post-list-$page_number"); | ||||
| 					$images = $database->cache->get("post-list:$page_number"); | ||||
| 					if(!$images) { | ||||
| 						$images = Image::find_images(($page_number-1)*$page_size, $page_size, $search_terms); | ||||
| 						$database->cache->set("post-list-$page_number", $images, 600); | ||||
| 						$database->cache->set("post-list:$page_number", $images, 600); | ||||
| 					} | ||||
| 				} | ||||
| 				else { | ||||
|  | ||||
| @ -28,37 +28,13 @@ and of course start organising your images :-) | ||||
| 	} | ||||
| 
 | ||||
| 	public function display_page(Page $page, $images) { | ||||
| 		global $config; | ||||
| 
 | ||||
| 		if(count($this->search_terms) == 0) { | ||||
| 			$query = null; | ||||
| 			$page_title = $config->get_string('title'); | ||||
| 		} | ||||
| 		else { | ||||
| 			$search_string = implode(' ', $this->search_terms); | ||||
| 			$query = url_escape($search_string); | ||||
| 			$page_title = html_escape($search_string); | ||||
| 			if(count($images) > 0) { | ||||
| 				$page->set_subheading("Page {$this->page_number} / {$this->total_pages}"); | ||||
| 			} | ||||
| 		} | ||||
| 		if($this->page_number > 1 || count($this->search_terms) > 0) { | ||||
| 			// $page_title .= " / $page_number";
 | ||||
| 		} | ||||
| 		$this->display_page_header($page, $images); | ||||
| 
 | ||||
| 		$nav = $this->build_navigation($this->page_number, $this->total_pages, $this->search_terms); | ||||
| 		$page->set_title($page_title); | ||||
| 		$page->set_heading($page_title); | ||||
| 		$page->add_block(new Block("Navigation", $nav, "left", 0)); | ||||
| 
 | ||||
| 		if(count($images) > 0) { | ||||
| 			if($query) { | ||||
| 				$page->add_block(new Block("Images", $this->build_table($images, "#search=$query"), "main", 10, "image-list")); | ||||
| 				$this->display_paginator($page, "post/list/$query", null, $this->page_number, $this->total_pages); | ||||
| 			} | ||||
| 			else { | ||||
| 				$page->add_block(new Block("Images", $this->build_table($images, null), "main", 10, "image-list")); | ||||
| 				$this->display_paginator($page, "post/list", null, $this->page_number, $this->total_pages); | ||||
| 			} | ||||
| 			$this->display_page_images($page, $images); | ||||
| 		} | ||||
| 		else { | ||||
| 			$this->display_error(404, "No Images Found", "No images were found to match the search criteria"); | ||||
| @ -105,5 +81,36 @@ and of course start organising your images :-) | ||||
| 		$table .= "</div>"; | ||||
| 		return $table; | ||||
| 	} | ||||
| 
 | ||||
| 	protected function display_page_header(Page $page, $images) { | ||||
| 		global $config; | ||||
| 
 | ||||
| 		if (count($this->search_terms) == 0) { | ||||
| 			$page_title = $config->get_string('title'); | ||||
| 		} else { | ||||
| 			$search_string = implode(' ', $this->search_terms); | ||||
| 			$page_title = html_escape($search_string); | ||||
| 			if (count($images) > 0) { | ||||
| 				$page->set_subheading("Page {$this->page_number} / {$this->total_pages}"); | ||||
| 			} | ||||
| 		} | ||||
| 		if ($this->page_number > 1 || count($this->search_terms) > 0) { | ||||
| 			// $page_title .= " / $page_number";
 | ||||
| 		} | ||||
| 
 | ||||
| 		$page->set_title($page_title); | ||||
| 		$page->set_heading($page_title); | ||||
| 	} | ||||
| 
 | ||||
| 	protected function display_page_images(Page $page, $images) { | ||||
| 		if (count($this->search_terms) > 0) { | ||||
| 			$query = url_escape(implode(' ', $this->search_terms)); | ||||
| 			$page->add_block(new Block("Images", $this->build_table($images, "#search=$query"), "main", 10, "image-list")); | ||||
| 			$this->display_paginator($page, "post/list/$query", null, $this->page_number, $this->total_pages); | ||||
| 		} else { | ||||
| 			$page->add_block(new Block("Images", $this->build_table($images, null), "main", 10, "image-list")); | ||||
| 			$this->display_paginator($page, "post/list", null, $this->page_number, $this->total_pages); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										
											BIN
										
									
								
								ext/notes/border-h.gif
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								ext/notes/border-h.gif
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 72 B | 
							
								
								
									
										
											BIN
										
									
								
								ext/notes/border-v.gif
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								ext/notes/border-v.gif
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 72 B | 
| @ -238,8 +238,11 @@ class Notes extends Extension { | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	/* | ||||
| 	 * HERE WE GET ALL NOTES FOR DISPLAYED IMAGE | ||||
| 	/** | ||||
| 	 * HERE WE GET ALL NOTES FOR DISPLAYED IMAGE. | ||||
| 	 * | ||||
| 	 * @param int $imageID | ||||
| 	 * @return array | ||||
| 	 */ | ||||
| 	private function get_notes($imageID) { | ||||
| 		global $database; | ||||
| @ -347,7 +350,6 @@ class Notes extends Extension { | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 	/* | ||||
| 	* HERE WE DELETE THE NOTE | ||||
| 	*/ | ||||
| @ -400,13 +402,15 @@ class Notes extends Extension { | ||||
| 		log_info("notes", "Requests deleted from {$image_id} by {$user->name}"); | ||||
| 	} | ||||
| 
 | ||||
| 		 | ||||
| 		 | ||||
| 	/* | ||||
| 	/** | ||||
| 	 * HERE WE ALL IMAGES THAT HAVE NOTES | ||||
| 	 * @param PageRequestEvent $event | ||||
| 	 */ | ||||
| 	private function get_notes_list($event) { | ||||
| 	private function get_notes_list(PageRequestEvent $event) { | ||||
| 		global $database, $config; | ||||
| 
 | ||||
| 		$pageNumber = $event->get_arg(1); | ||||
| 
 | ||||
| 		if(is_null($pageNumber) || !is_numeric($pageNumber)) | ||||
| 		$pageNumber = 0; | ||||
| 		else if ($pageNumber <= 0) | ||||
| @ -414,13 +418,10 @@ class Notes extends Extension { | ||||
| 		else | ||||
| 		$pageNumber--; | ||||
| 
 | ||||
|             global $config; | ||||
|              | ||||
| 		$notesPerPage = $config->get_int('notesNotesPerPage'); | ||||
| 	 | ||||
| 				 | ||||
| 		//$result = $database->get_all("SELECT * FROM pool_images WHERE pool_id=?", array($poolID));
 | ||||
| 		global $database; | ||||
| 
 | ||||
| 		$get_notes = " | ||||
| 			SELECT DISTINCT image_id ".
 | ||||
| 			"FROM notes ". | ||||
| @ -441,13 +442,15 @@ class Notes extends Extension { | ||||
| 		$this->theme->display_note_list($images, $pageNumber + 1, $totalPages); | ||||
| 	} | ||||
| 
 | ||||
| 	 | ||||
| 	 | ||||
| 	/* | ||||
| 	/** | ||||
| 	 * HERE WE GET ALL NOTE REQUESTS | ||||
| 	 * @param PageRequestEvent $event | ||||
| 	 */ | ||||
| 	private function get_notes_requests($event) { | ||||
| 	private function get_notes_requests(PageRequestEvent $event) { | ||||
| 		global $config; | ||||
| 
 | ||||
| 		$pageNumber = $event->get_arg(1); | ||||
| 
 | ||||
| 		if(is_null($pageNumber) || !is_numeric($pageNumber)) | ||||
| 			$pageNumber = 0; | ||||
| 		else if ($pageNumber <= 0) | ||||
| @ -455,8 +458,6 @@ class Notes extends Extension { | ||||
| 		else | ||||
| 			$pageNumber--; | ||||
| 
 | ||||
|             global $config; | ||||
|              | ||||
| 		$requestsPerPage = $config->get_int('notesRequestsPerPage'); | ||||
| 
 | ||||
| 
 | ||||
| @ -503,11 +504,11 @@ class Notes extends Extension { | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	 | ||||
| 	/* | ||||
| 	/** | ||||
| 	 * HERE WE GET ALL HISTORIES. | ||||
| 	 * @param PageRequestEvent $event | ||||
| 	 */ | ||||
| 	private function get_histories($event){ | ||||
| 	private function get_histories(PageRequestEvent $event){ | ||||
| 		$pageNumber = $event->get_arg(1); | ||||
|             if(is_null($pageNumber) || !is_numeric($pageNumber)) | ||||
|                 $pageNumber = 0; | ||||
| @ -535,11 +536,11 @@ class Notes extends Extension { | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	 | ||||
| 	/* | ||||
| 	/** | ||||
| 	 * HERE WE THE HISTORY FOR A SPECIFIC NOTE. | ||||
| 	 * @param PageRequestEvent $event | ||||
| 	 */ | ||||
| 	private function get_history($event){ | ||||
| 	private function get_history(PageRequestEvent $event){ | ||||
| 		$noteID = $event->get_arg(1); | ||||
| 		$pageNumber = $event->get_arg(2); | ||||
|             if(is_null($pageNumber) || !is_numeric($pageNumber)) | ||||
| @ -567,13 +568,13 @@ class Notes extends Extension { | ||||
| 		$this->theme->display_history($histories, $pageNumber + 1, $totalPages); | ||||
| 	} | ||||
| 
 | ||||
| 	 | ||||
| 	 | ||||
| 	/* | ||||
| 	* HERE GO BACK IN HISTORY AND SET THE OLD NOTE. IF WAS REMOVED WE READD IT. | ||||
| 	/** | ||||
| 	 * HERE GO BACK IN HISTORY AND SET THE OLD NOTE. IF WAS REMOVED WE RE-ADD IT. | ||||
| 	 * @param int $noteID | ||||
| 	 * @param int $reviewID | ||||
| 	 */ | ||||
| 	private function revert_history($noteID, $reviewID){ | ||||
| 		global $user, $database; | ||||
| 		global $database; | ||||
| 		 | ||||
| 		$history = $database->get_row("SELECT * FROM note_histories WHERE note_id = ? AND review_id = ?",array($noteID, $reviewID)); | ||||
| 		 | ||||
| @ -596,7 +597,6 @@ class Notes extends Extension { | ||||
| 						   "WHERE image_id = ? AND id = ?", array(1, $noteX1, $noteY1, $noteHeight, $noteWidth, $noteText, $imageID, $noteID)); | ||||
| 								   | ||||
| 		$this->add_history($noteEnable, $noteID, $imageID, $noteX1, $noteY1, $noteHeight, $noteWidth, $noteText); | ||||
| 		 | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -2,7 +2,9 @@ | ||||
| 
 | ||||
| $(function() { | ||||
| 	if(window.notes) { | ||||
| 		$('#main_image').load(function(){ | ||||
| 			$('#main_image').imgNotes({notes: window.notes}); | ||||
| 		}); | ||||
| 	} | ||||
| 
 | ||||
| 	$('#cancelnote').click(function(){ | ||||
|  | ||||
| @ -33,3 +33,45 @@ | ||||
| #noteform textarea, #noteEditForm textarea { | ||||
| 	width: 100%; | ||||
| } | ||||
| 
 | ||||
| /* | ||||
|  * imgAreaSelect default style | ||||
|  */ | ||||
| 
 | ||||
| .imgareaselect-border1 { | ||||
| 	background: url(border-v.gif) repeat-y left top; | ||||
| } | ||||
| 
 | ||||
| .imgareaselect-border2 { | ||||
|     background: url(border-h.gif) repeat-x left top; | ||||
| } | ||||
| 
 | ||||
| .imgareaselect-border3 { | ||||
|     background: url(border-v.gif) repeat-y right top; | ||||
| } | ||||
| 
 | ||||
| .imgareaselect-border4 { | ||||
|     background: url(border-h.gif) repeat-x left bottom; | ||||
| } | ||||
| 
 | ||||
| .imgareaselect-border1, .imgareaselect-border2, | ||||
| .imgareaselect-border3, .imgareaselect-border4 { | ||||
|     filter: alpha(opacity=50); | ||||
| 	opacity: 0.5; | ||||
| } | ||||
| 
 | ||||
| .imgareaselect-handle { | ||||
|     background-color: #fff; | ||||
|     border: solid 1px #000; | ||||
|     filter: alpha(opacity=50); | ||||
|     opacity: 0.5; | ||||
| } | ||||
| 
 | ||||
| .imgareaselect-outer { | ||||
|     /*background-color: #000;*/ | ||||
|     filter: alpha(opacity=50); | ||||
|     opacity: 0.5; | ||||
| } | ||||
| 
 | ||||
| .imgareaselect-selection {   | ||||
| } | ||||
| @ -284,6 +284,11 @@ class NumericScore extends Extension { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param int $image_id | ||||
| 	 * @param int $user_id | ||||
| 	 * @param int $score | ||||
| 	 */ | ||||
| 	private function add_vote(/*int*/ $image_id, /*int*/ $user_id, /*int*/ $score) { | ||||
| 		global $database; | ||||
| 		$database->execute( | ||||
|  | ||||
| @ -58,7 +58,7 @@ class NumericScoreTheme extends Themelet { | ||||
| 			<input type='submit' value='Delete all votes by this user'> | ||||
| 			</form> | ||||
| 		";
 | ||||
| 		$page->add_block(new Block("Votes", $html, "main", 60)); | ||||
| 		$page->add_block(new Block("Votes", $html, "main", 80)); | ||||
| 	} | ||||
| 
 | ||||
| 	public function view_popular($images, $dte) { | ||||
|  | ||||
| @ -197,7 +197,7 @@ class PrivMsg extends Extension { | ||||
| 	private function count_pms(User $user) { | ||||
| 		global $database; | ||||
| 
 | ||||
| 		$count = $database->cache->get("pm-count-{$user->id}"); | ||||
| 		$count = $database->cache->get("pm-count:{$user->id}"); | ||||
| 		if(is_null($count) || $count === false) { | ||||
| 			$count = $database->get_one(" | ||||
| 					SELECT count(*) | ||||
| @ -205,7 +205,7 @@ class PrivMsg extends Extension { | ||||
| 					WHERE to_id = :to_id | ||||
| 					AND is_read = :is_read | ||||
| 			", array("to_id" => $user->id, "is_read" => "N"));
 | ||||
| 			$database->cache->set("pm-count-{$user->id}", $count, 600); | ||||
| 			$database->cache->set("pm-count:{$user->id}", $count, 600); | ||||
| 		} | ||||
| 		return $count; | ||||
| 	} | ||||
|  | ||||
| @ -39,7 +39,7 @@ class PrivMsgTheme extends Themelet { | ||||
| 				</tbody> | ||||
| 			</table> | ||||
| 		";
 | ||||
| 		$page->add_block(new Block("Private Messages", $html, "main", 10, "private-messages")); | ||||
| 		$page->add_block(new Block("Private Messages", $html, "main", 40, "private-messages")); | ||||
| 	} | ||||
| 
 | ||||
| 	public function display_composer(Page $page, User $from, User $to, $subject="") { | ||||
| @ -59,7 +59,7 @@ $auth | ||||
| </table> | ||||
| </form> | ||||
| EOD; | ||||
| 		$page->add_block(new Block("Write a PM", $html, "main", 20)); | ||||
| 		$page->add_block(new Block("Write a PM", $html, "main", 50)); | ||||
| 	} | ||||
| 
 | ||||
| 	public function display_message(Page $page, User $from, User $to, PM $pm) { | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| <?php | ||||
| /** | ||||
|  * Name: Pools System | ||||
|  * Author: Sein Kraft <mail@seinkraft.info>, jgen <jgen.tech@gmail.com> | ||||
|  * Author: Sein Kraft <mail@seinkraft.info>, jgen <jgen.tech@gmail.com>, Daku <admin@codeanimu.net> | ||||
|  * License: GPLv2 | ||||
|  * Description: Allow users to create groups of images and order them. | ||||
|  * Documentation: This extension allows users to created named groups of | ||||
| @ -13,8 +13,12 @@ | ||||
|  * This class is just a wrapper around SCoreException. | ||||
|  */ | ||||
| class PoolCreationException extends SCoreException { | ||||
| 	var $error; | ||||
| 	/** @var string */ | ||||
| 	public $error; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $error | ||||
| 	 */ | ||||
| 	public function __construct($error) { | ||||
| 		$this->error = $error; | ||||
| 	} | ||||
| @ -76,6 +80,13 @@ class Pools extends Extension { | ||||
| 
 | ||||
| 			$config->set_int("ext_pools_version", 2); | ||||
| 		} | ||||
| 
 | ||||
| 		if ($config->get_int("ext_pools_version") < 3){ | ||||
| 			$config->set_bool("poolsShowNavLinks","N"); //A $config->rename() function would be nice here...
 | ||||
| 			$config->set_bool("poolsAutoIncrementOrder","N"); | ||||
| 
 | ||||
| 			$config->set_int("ext_pools_version", 3); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// Add a block to the Board Config / Setup
 | ||||
| @ -86,16 +97,17 @@ class Pools extends Extension { | ||||
| 		$sb->add_int_option("poolsListsPerPage", "<br>Index list items per page: "); | ||||
| 		$sb->add_int_option("poolsUpdatedPerPage", "<br>Updated list items per page: "); | ||||
| 		$sb->add_bool_option("poolsInfoOnViewImage", "<br>Show pool info on image: "); | ||||
| 		$sb->add_bool_option("poolsShowNextLink", "<br>Show 'Next' link when viewing pool images: "); | ||||
| 		$sb->add_bool_option("poolsShowNavLinks", "<br>Show 'Prev' & 'Next' links when viewing pool images: "); | ||||
| 		$sb->add_bool_option("poolsAutoIncrementOrder", "<br>Autoincrement order when post is added to pool:"); | ||||
| 		//$sb->add_bool_option("poolsAdderOnViewImage", "<br>Show pool adder on image: ");
 | ||||
| 
 | ||||
| 		$event->panel->add_block($sb); | ||||
| 	} | ||||
| 
 | ||||
| 	public function onPageRequest(PageRequestEvent $event) { | ||||
| 		global $config, $page, $user; | ||||
| 		global $page, $user; | ||||
| 		 | ||||
| 		if ($event->page_matches("pool")) { | ||||
| 
 | ||||
| 			$pool_id = 0; | ||||
| 			$pool = array(); | ||||
| 
 | ||||
| @ -249,30 +261,27 @@ class Pools extends Extension { | ||||
| 	 * to the Next image in the pool. | ||||
| 	 */ | ||||
| 	public function onDisplayingImage(DisplayingImageEvent $event) { | ||||
| 		global $config, $database, $page; | ||||
| 		global $config; | ||||
| 
 | ||||
| 		if($config->get_bool("poolsInfoOnViewImage")) { | ||||
| 			$imageID = $event->image->id; | ||||
| 			$poolsIDs = $this->get_pool_id($imageID); | ||||
| 
 | ||||
| 			$show_next = $config->get_bool("poolsShowNextLink", false); | ||||
| 			$show_nav = $config->get_bool("poolsShowNavLinks", false); | ||||
| 
 | ||||
| 			$linksPools = array(); | ||||
| 			$navInfo = array(); | ||||
| 			foreach($poolsIDs as $poolID) { | ||||
| 				$pools = $this->get_pool($poolID['pool_id']); | ||||
| 				foreach ($pools as $pool){ | ||||
| 					$linksPools[] = "<a href='".make_link("pool/view/".$pool['id'])."'>".html_escape($pool['title'])."</a>"; | ||||
| 				$pool = $this->get_single_pool($poolID['pool_id']); | ||||
| 
 | ||||
| 					// Optionally show a link the Next image in the Pool.
 | ||||
| 					if ($show_next) { | ||||
| 						$next_image_in_pool = $this->get_next_post($pool, $imageID); | ||||
| 						if (!empty($next_image_in_pool)) { | ||||
| 							$linksPools[] = '<a href="'.make_link('post/view/'.$next_image_in_pool).'" class="pools_next_img">Next</a>'; | ||||
| 				$navInfo[$pool['id']] = array(); | ||||
| 				$navInfo[$pool['id']]['info'] = $pool; | ||||
| 
 | ||||
| 				// Optionally show a link the Prev/Next image in the Pool.
 | ||||
| 				if ($show_nav) { | ||||
| 					$navInfo[$pool['id']]['nav'] = $this->get_nav_posts($pool, $imageID); | ||||
| 				} | ||||
| 			} | ||||
| 				} | ||||
| 			} | ||||
| 			$this->theme->pool_info($linksPools); | ||||
| 			$this->theme->pool_info($navInfo); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| @ -316,19 +325,24 @@ class Pools extends Extension { | ||||
| 	public function onTagTermParse(TagTermParseEvent $event) { | ||||
| 		$matches = array(); | ||||
| 
 | ||||
| 		if(preg_match("/^pool[=|:](.*)$/i", $event->term, $matches)) { | ||||
| 		if(preg_match("/^pool[=|:]([^:]*|lastcreated):?([0-9]*)$/i", $event->term, $matches)) { | ||||
| 			global $user; | ||||
| 			$poolTag = (string) str_replace("_", " ", $matches[1]); | ||||
| 
 | ||||
| 			$pool = null; | ||||
| 			if(ctype_digit($poolTag)){ //If only digits, assume PoolID
 | ||||
| 			if($poolTag == 'lastcreated'){ | ||||
| 				$pool = $this->get_last_userpool($user->id); | ||||
| 			} | ||||
| 			elseif(ctype_digit($poolTag)){ //If only digits, assume PoolID
 | ||||
| 				$pool = $this->get_single_pool($poolTag); | ||||
| 			}else{ //assume PoolTitle
 | ||||
| 				$pool = $this->get_single_pool_from_title($poolTag); | ||||
| 			} | ||||
| 
 | ||||
| 
 | ||||
| 			if($pool ? $this->have_permission($user, $pool) : FALSE){ | ||||
| 				$this->add_post($pool['id'], $event->id, true); | ||||
| 				$image_order = ($matches[2] ?: 0); | ||||
| 				$this->add_post($pool['id'], $event->id, true, $image_order); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| @ -341,7 +355,11 @@ class Pools extends Extension { | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Check if the given user has permission to edit/change the pool. | ||||
| 	 * | ||||
| 	 * TODO: Should the user variable be global? | ||||
| 	 * | ||||
| 	 * @param \User $user | ||||
| 	 * @param array $pool | ||||
| 	 * @return bool | ||||
| 	 */ | ||||
| 	private function have_permission($user, $pool) { | ||||
| @ -354,8 +372,11 @@ class Pools extends Extension { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/* | ||||
| 	 * HERE WE GET THE LIST OF POOLS | ||||
| 	/** | ||||
| 	 * HERE WE GET THE LIST OF POOLS. | ||||
| 	 * | ||||
| 	 * @param \Page $page | ||||
| 	 * @param int $pageNumber | ||||
| 	 */ | ||||
| 	private function list_pools(Page $page, /*int*/ $pageNumber) { | ||||
| 		global $config, $database; | ||||
| @ -399,8 +420,11 @@ class Pools extends Extension { | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	/* | ||||
| 	/** | ||||
| 	 * HERE WE CREATE A NEW POOL | ||||
| 	 * | ||||
| 	 * @return mixed | ||||
| 	 * @throws PoolCreationException | ||||
| 	 */ | ||||
| 	private function add_pool() { | ||||
| 		global $user, $database; | ||||
| @ -431,8 +455,11 @@ class Pools extends Extension { | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Retrieve information about pools given multiple pool IDs. | ||||
| 	 * @param $poolID Array of integers | ||||
| 	 * @return 2D Array | ||||
| 	 * | ||||
| 	 * TODO: What is the difference between this and get_single_pool() other than the db query? | ||||
| 	 * | ||||
| 	 * @param int $poolID Array of integers | ||||
| 	 * @return array | ||||
| 	 */ | ||||
| 	private function get_pool(/*int*/ $poolID) { | ||||
| 		global $database; | ||||
| @ -441,8 +468,8 @@ class Pools extends Extension { | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Retrieve information about a pool given a pool ID. | ||||
| 	 * @param $poolID Integer | ||||
| 	 * @return 2D array (with only 1 element in the one dimension) | ||||
| 	 * @param int $poolID the pool id | ||||
| 	 * @return array Array with only 1 element in the one dimension | ||||
| 	 */ | ||||
| 	private function get_single_pool(/*int*/ $poolID) { | ||||
| 		global $database; | ||||
| @ -451,8 +478,8 @@ class Pools extends Extension { | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Retrieve information about a pool given a pool title. | ||||
| 	 * @param $poolTitle Integer | ||||
| 	 * @return 2D array (with only 1 element in the one dimension) | ||||
| 	 * @param string $poolTitle | ||||
| 	 * @return array Array (with only 1 element in the one dimension) | ||||
| 	 */ | ||||
| 	private function get_single_pool_from_title(/*string*/ $poolTitle) { | ||||
| 		global $database; | ||||
| @ -461,32 +488,44 @@ class Pools extends Extension { | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Get all of the pool IDs that an image is in, given an image ID. | ||||
| 	 * @param $imageID Integer | ||||
| 	 * @return 2D array | ||||
| 	 * @param int $imageID Integer ID for the image | ||||
| 	 * @return array | ||||
| 	 */ | ||||
| 	private function get_pool_id(/*int*/ $imageID) { | ||||
| 		global $database; | ||||
| 		return $database->get_all("SELECT pool_id FROM pool_images WHERE image_id=:iid", array("iid"=>$imageID)); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Retrieve information about the last pool the given userID created | ||||
| 	 * @param int $userID | ||||
| 	 * @return array | ||||
| 	 */ | ||||
| 	private function get_last_userpool(/*int*/ $userID){ | ||||
| 		global $database; | ||||
| 		return $database->get_row("SELECT * FROM pools WHERE user_id=:uid ORDER BY id DESC", array("uid"=>$userID)); | ||||
| 	} | ||||
| 
 | ||||
| 	/* | ||||
| 	/** | ||||
| 	 * HERE WE GET THE IMAGES FROM THE TAG ON IMPORT | ||||
| 	 * @param int $pool_id | ||||
| 	 */ | ||||
| 	private function import_posts(/*int*/ $pool_id) { | ||||
| 		global $page, $config, $database; | ||||
| 		global $page, $config; | ||||
| 
 | ||||
| 		$poolsMaxResults = $config->get_int("poolsMaxImportResults", 1000); | ||||
| 		 | ||||
| 		$images = $images = Image::find_images(0, $poolsMaxResults, Tag::explode($_POST["pool_tag"])); | ||||
| 		$this->theme->pool_result($page, $images, $pool_id); | ||||
| 		$this->theme->pool_result($page, $images, $this->get_pool($pool_id)); | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	/* | ||||
| 	/** | ||||
| 	 * HERE WE ADD CHECKED IMAGES FROM POOL AND UPDATE THE HISTORY | ||||
| 	 * | ||||
| 	 * TODO: Fix this so that the pool ID and images are passed as Arguments to the function. | ||||
| 	 * | ||||
| 	 * @return int | ||||
| 	 */ | ||||
| 	private function add_posts() { | ||||
| 		global $database; | ||||
| @ -503,11 +542,10 @@ class Pools extends Extension { | ||||
| 
 | ||||
| 				$images .= " ".$imageID; | ||||
| 			} | ||||
| 
 | ||||
| 		} | ||||
| 
 | ||||
| 		if(!strlen($images) == 0) { | ||||
| 			$count = $database->get_one("SELECT COUNT(*) FROM pool_images WHERE pool_id=:pid", array("pid"=>$poolID)); | ||||
| 			$count = int_escape($database->get_one("SELECT COUNT(*) FROM pool_images WHERE pool_id=:pid", array("pid"=>$poolID))); | ||||
| 			$this->add_history($poolID, 1, $images, $count); | ||||
| 		} | ||||
| 
 | ||||
| @ -520,8 +558,9 @@ class Pools extends Extension { | ||||
| 		return $poolID; | ||||
| 	} | ||||
| 
 | ||||
| 	/* | ||||
| 	/** | ||||
| 	 * TODO: Fix this so that the pool ID and images are passed as Arguments to the function. | ||||
| 	 * @return int | ||||
| 	 */ | ||||
| 	private function order_posts() { | ||||
| 		global $database; | ||||
| @ -541,11 +580,12 @@ class Pools extends Extension { | ||||
| 		return $poolID; | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	/* | ||||
| 	/** | ||||
| 	 * HERE WE REMOVE CHECKED IMAGES FROM POOL AND UPDATE THE HISTORY | ||||
| 	 * | ||||
| 	 * TODO: Fix this so that the pool ID and images are passed as Arguments to the function. | ||||
| 	 * | ||||
| 	 * @return int | ||||
| 	 */ | ||||
| 	private function remove_posts() { | ||||
| 		global $database; | ||||
| @ -563,8 +603,9 @@ class Pools extends Extension { | ||||
| 		return $poolID; | ||||
| 	} | ||||
| 
 | ||||
| 	/* | ||||
| 	/** | ||||
| 	 * Allows editing of pool description. | ||||
| 	 * @return int | ||||
| 	 */ | ||||
| 	private function edit_description() { | ||||
| 		global $database; | ||||
| @ -580,8 +621,8 @@ class Pools extends Extension { | ||||
| 	 * Used by add_posts() | ||||
| 	 * | ||||
| 	 * @see add_posts() | ||||
| 	 * @param $poolID integer | ||||
| 	 * @param $imageID integer | ||||
| 	 * @param int $poolID | ||||
| 	 * @param int $imageID | ||||
| 	 * @return bool | ||||
| 	 */ | ||||
| 	private function check_post(/*int*/ $poolID, /*int*/ $imageID) { | ||||
| @ -591,24 +632,47 @@ class Pools extends Extension { | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Gets the next successive image from a pool, given a pool ID and an image ID. | ||||
| 	 * Gets the previous and next successive images from a pool, given a pool ID and an image ID. | ||||
| 	 * | ||||
| 	 * @param $pool Array for the given pool | ||||
| 	 * @param $imageID Integer | ||||
| 	 * @return Integer which is the next Image ID or NULL if none. | ||||
| 	 * @param array $pool Array for the given pool | ||||
| 	 * @param int $imageID Integer | ||||
| 	 * @return array Array returning two elements (prev, next) in 1 dimension. Each returns ImageID or NULL if none. | ||||
| 	 */ | ||||
| 	private function get_next_post(/*array*/ $pool, /*int*/ $imageID) { | ||||
| 	private function get_nav_posts(/*array*/ $pool, /*int*/ $imageID) { | ||||
| 		global $database; | ||||
| 
 | ||||
| 		if (empty($pool) || empty($imageID)) | ||||
| 			return null; | ||||
| 		 | ||||
| 		$result = $database->get_one(" | ||||
| 		$result = $database->get_row(" | ||||
| 						SELECT ( | ||||
| 							SELECT image_id | ||||
| 							FROM pool_images | ||||
| 					WHERE pool_id=:pid | ||||
| 					AND image_order > (SELECT image_order FROM pool_images WHERE pool_id=:pid AND image_id =:iid LIMIT 1 ) | ||||
| 					ORDER BY image_order ASC LIMIT 1",
 | ||||
| 							WHERE pool_id = :pid | ||||
| 							AND image_order < ( | ||||
| 								SELECT image_order | ||||
| 								FROM pool_images | ||||
| 								WHERE pool_id = :pid | ||||
| 								AND image_id = :iid | ||||
| 								LIMIT 1 | ||||
| 							) | ||||
| 							ORDER BY image_order DESC LIMIT 1 | ||||
| 						) AS prev, | ||||
| 						( | ||||
| 							SELECT image_id | ||||
| 							FROM pool_images | ||||
| 							WHERE pool_id = :pid | ||||
| 							AND image_order > ( | ||||
| 								SELECT image_order | ||||
| 								FROM pool_images | ||||
| 								WHERE pool_id = :pid | ||||
| 								AND image_id = :iid | ||||
| 								LIMIT 1 | ||||
| 							) | ||||
| 							ORDER BY image_order ASC LIMIT 1 | ||||
| 						) AS next | ||||
| 
 | ||||
| 						LIMIT 1",
 | ||||
| 					array("pid"=>$pool['id'], "iid"=>$imageID) ); | ||||
| 
 | ||||
| 		if (empty($result)) { | ||||
| @ -621,6 +685,9 @@ class Pools extends Extension { | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Retrieve all the images in a pool, given a pool ID. | ||||
| 	 * | ||||
| 	 * @param PageRequestEvent $event | ||||
| 	 * @param int $poolID | ||||
| 	 */ | ||||
| 	private function get_posts($event, /*int*/ $poolID) { | ||||
| 		global $config, $user, $database; | ||||
| @ -684,8 +751,8 @@ class Pools extends Extension { | ||||
| 
 | ||||
| 	/** | ||||
| 	 * This function gets the current order of images from a given pool. | ||||
| 	 * @param $poolID integer | ||||
| 	 * @return Array of image objects. | ||||
| 	 * @param int $poolID | ||||
| 	 * @return \Image[] Array of image objects. | ||||
| 	 */ | ||||
| 	private function edit_posts(/*int*/ $poolID) { | ||||
| 		global $database; | ||||
| @ -702,8 +769,11 @@ class Pools extends Extension { | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	/* | ||||
| 	 * WE GET THE ORDER OF THE IMAGES BUT HERE WE SEND KEYS ADDED IN ARRAY TO GET THE ORDER IN THE INPUT VALUE | ||||
| 	/** | ||||
| 	 * WE GET THE ORDER OF THE IMAGES BUT HERE WE SEND KEYS ADDED IN ARRAY TO GET THE ORDER IN THE INPUT VALUE. | ||||
| 	 * | ||||
| 	 * @param int $poolID | ||||
| 	 * @return \Image[] | ||||
| 	 */ | ||||
| 	private function edit_order(/*int*/ $poolID) { | ||||
| 		global $database; | ||||
| @ -726,8 +796,10 @@ class Pools extends Extension { | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	/* | ||||
| 	 * HERE WE NUKE ENTIRE POOL. WE REMOVE POOLS AND POSTS FROM REMOVED POOL AND HISTORIES ENTRIES FROM REMOVED POOL | ||||
| 	/** | ||||
| 	 * HERE WE NUKE ENTIRE POOL. WE REMOVE POOLS AND POSTS FROM REMOVED POOL AND HISTORIES ENTRIES FROM REMOVED POOL. | ||||
| 	 * | ||||
| 	 * @param int $poolID | ||||
| 	 */ | ||||
| 	private function nuke_pool(/*int*/ $poolID) { | ||||
| 		global $user, $database; | ||||
| @ -744,10 +816,13 @@ class Pools extends Extension { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	/* | ||||
| 	 * HERE WE ADD A HISTORY ENTRY | ||||
| 	 * FOR $action 1 (one) MEANS ADDED, 0 (zero) MEANS REMOVED | ||||
| 	/** | ||||
| 	 * HERE WE ADD A HISTORY ENTRY. | ||||
| 	 * | ||||
| 	 * @param int $poolID | ||||
| 	 * @param int $action Action=1 (one) MEANS ADDED, Action=0 (zero) MEANS REMOVED | ||||
| 	 * @param string $images | ||||
| 	 * @param int $count | ||||
| 	 */ | ||||
| 	private function add_history(/*int*/ $poolID, $action, $images, $count) { | ||||
| 		global $user, $database; | ||||
| @ -758,9 +833,9 @@ class Pools extends Extension { | ||||
| 				array("pid"=>$poolID, "uid"=>$user->id, "act"=>$action, "img"=>$images, "count"=>$count)); | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	/* | ||||
| 	 * HERE WE GET THE HISTORY LIST | ||||
| 	/** | ||||
| 	 * HERE WE GET THE HISTORY LIST. | ||||
| 	 * @param int $pageNumber | ||||
| 	 */ | ||||
| 	private function get_history(/*int*/ $pageNumber) { | ||||
| 		global $config, $database; | ||||
| @ -772,7 +847,6 @@ class Pools extends Extension { | ||||
| 		else | ||||
| 			$pageNumber--; | ||||
| 
 | ||||
| 
 | ||||
| 		$historiesPerPage = $config->get_int("poolsUpdatedPerPage"); | ||||
| 
 | ||||
| 		$history = $database->get_all(" | ||||
| @ -792,10 +866,9 @@ class Pools extends Extension { | ||||
| 		$this->theme->show_history($history, $pageNumber + 1, $totalPages); | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 	/* | ||||
| 	 * HERE GO BACK IN HISTORY AND ADD OR REMOVE POSTS TO POOL | ||||
| 	/** | ||||
| 	 * HERE GO BACK IN HISTORY AND ADD OR REMOVE POSTS TO POOL. | ||||
| 	 * @param int $historyID | ||||
| 	 */ | ||||
| 	private function revert_history(/*int*/ $historyID) { | ||||
| 		global $database; | ||||
| @ -838,20 +911,31 @@ class Pools extends Extension { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 	/* | ||||
| 	 * HERE WE ADD A SIMPLE POST FROM POOL | ||||
| 	 * USED WITH FOREACH IN revert_history() & onTagTermParse() | ||||
| 	/** | ||||
| 	 * HERE WE ADD A SIMPLE POST FROM POOL. | ||||
| 	 * USED WITH FOREACH IN revert_history() & onTagTermParse(). | ||||
| 	 * | ||||
| 	 * @param int $poolID | ||||
| 	 * @param int $imageID | ||||
| 	 * @param bool $history | ||||
| 	 * @param int $imageOrder | ||||
| 	 */ | ||||
| 	private function add_post(/*int*/ $poolID, /*int*/ $imageID, $history=false) { | ||||
| 		global $database; | ||||
| 	private function add_post(/*int*/ $poolID, /*int*/ $imageID, $history=false, $imageOrder=0) { | ||||
| 		global $database, $config; | ||||
| 
 | ||||
| 		if(!$this->check_post($poolID, $imageID)) { | ||||
| 			if($config->get_bool("poolsAutoIncrementOrder") && $imageOrder === 0){ | ||||
| 				$imageOrder = $database->get_one(" | ||||
| 						SELECT CASE WHEN image_order IS NOT NULL THEN MAX(image_order) + 1 ELSE 0 END | ||||
| 						FROM pool_images | ||||
| 						WHERE pool_id = :pid",
 | ||||
| 						array("pid"=>$poolID)); | ||||
| 			} | ||||
| 
 | ||||
| 			$database->execute(" | ||||
| 					INSERT INTO pool_images (pool_id, image_id) | ||||
| 					VALUES (:pid, :iid)",
 | ||||
| 					array("pid"=>$poolID, "iid"=>$imageID)); | ||||
| 					INSERT INTO pool_images (pool_id, image_id, image_order) | ||||
| 					VALUES (:pid, :iid, :ord)",
 | ||||
| 					array("pid"=>$poolID, "iid"=>$imageID, "ord"=>$imageOrder)); | ||||
| 		} | ||||
| 
 | ||||
| 		$database->execute("UPDATE pools SET posts=(SELECT COUNT(*) FROM pool_images WHERE pool_id=:pid) WHERE id=:pid", array("pid"=>$poolID)); | ||||
| @ -862,11 +946,13 @@ class Pools extends Extension { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 	/* | ||||
| 	 * HERE WE REMOVE A SIMPLE POST FROM POOL | ||||
| 	 * USED WITH FOREACH IN revert_history() & onTagTermParse() | ||||
| 	/** | ||||
| 	 * HERE WE REMOVE A SIMPLE POST FROM POOL. | ||||
| 	 * USED WITH FOREACH IN revert_history() & onTagTermParse(). | ||||
| 	 * | ||||
| 	 * @param int $poolID | ||||
| 	 * @param int $imageID | ||||
| 	 * @param bool $history | ||||
| 	 */ | ||||
| 	private function delete_post(/*int*/ $poolID, /*int*/ $imageID, $history=false) { | ||||
| 		global $database; | ||||
|  | ||||
							
								
								
									
										13
									
								
								ext/pools/style.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								ext/pools/style.css
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,13 @@ | ||||
| .pools_next_img { | ||||
| 	display: block; | ||||
| 	font-size: 77%; | ||||
| 	text-align: right; | ||||
| 	float: right; | ||||
| } | ||||
| 
 | ||||
| .pools_prev_img { | ||||
| 	display: block; | ||||
| 	font-size: 77%; | ||||
| 	text-align: left; | ||||
| 	float: left; | ||||
| } | ||||
| @ -3,14 +3,39 @@ | ||||
| class PoolsTheme extends Themelet { | ||||
| 	/** | ||||
| 	 * Adds a block to the panel with information on the pool(s) the image is in. | ||||
| 	 * @param array Multidimensional array containing pool id, info & nav IDs. | ||||
| 	 */ | ||||
| 	public function pool_info($linksPools) { | ||||
| 	public function pool_info(/*array*/ $navIDs) { | ||||
| 		global $page; | ||||
| 
 | ||||
| 		$linksPools = array(); | ||||
| 		foreach($navIDs as $poolID => $pool){ | ||||
| 			$linksPools[] = "<a href='".make_link("pool/view/".$poolID)."'>".html_escape($pool['info']['title'])."</a>"; | ||||
| 
 | ||||
| 			if (array_key_exists('nav', $pool)){ | ||||
| 				$navlinks = ""; | ||||
| 				if (!empty($pool['nav']['prev'])) { | ||||
| 					$navlinks .= '<a href="'.make_link('post/view/'.$pool['nav']['prev']).'" class="pools_prev_img">Prev</a>'; | ||||
| 				} | ||||
| 				if (!empty($pool['nav']['next'])) { | ||||
| 					$navlinks .= '<a href="'.make_link('post/view/'.$pool['nav']['next']).'" class="pools_next_img">Next</a>'; | ||||
| 				} | ||||
| 				if(!empty($navlinks)){ | ||||
| 					$linksPools[] = $navlinks; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		if(count($linksPools) > 0) { | ||||
| 			$page->add_block(new Block("Pools", implode("<br>", $linksPools), "left")); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param Image $image | ||||
| 	 * @param array $pools | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	public function get_adder_html(Image $image, /*array*/ $pools) { | ||||
| 		$h = ""; | ||||
| 		foreach($pools as $pool) { | ||||
| @ -27,9 +52,13 @@ class PoolsTheme extends Themelet { | ||||
| 		return $editor; | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	/* | ||||
| 	 * HERE WE SHOWS THE LIST OF POOLS | ||||
| 	/** | ||||
| 	 * HERE WE SHOWS THE LIST OF POOLS. | ||||
| 	 * | ||||
| 	 * @param Page $page | ||||
| 	 * @param array $pools | ||||
| 	 * @param int $pageNumber | ||||
| 	 * @param int $totalPages | ||||
| 	 */ | ||||
| 	public function list_pools(Page $page, /*array*/ $pools, /*int*/ $pageNumber, /*int*/ $totalPages) { | ||||
| 		global $user; | ||||
| @ -58,12 +87,6 @@ class PoolsTheme extends Themelet { | ||||
| 
 | ||||
| 		$html .= "</tbody></table>"; | ||||
| 
 | ||||
| 		$nav_html = ' | ||||
| 			<a href="'.make_link().'">Index</a> | ||||
| 			<br><a href="'.make_link("pool/new").'">Create Pool</a> | ||||
| 			<br><a href="'.make_link("pool/updated").'">Pool Changes</a> | ||||
| 		'; | ||||
| 
 | ||||
| 		$order_html = ' | ||||
| 			<select id="order_pool"> | ||||
| 			  <option value="created">Recently created</option> | ||||
| @ -73,17 +96,16 @@ class PoolsTheme extends Themelet { | ||||
| 			</select> | ||||
| 		'; | ||||
| 
 | ||||
| 		$blockTitle = "Pools"; | ||||
| 		$page->set_title(html_escape($blockTitle)); | ||||
| 		$page->set_heading(html_escape($blockTitle)); | ||||
| 		$page->add_block(new Block($blockTitle, $html, "main", 10)); | ||||
| 		$page->add_block(new Block("Navigation", $nav_html, "left", 10)); | ||||
| 		$this->display_top(null, "Pools"); | ||||
| 		$page->add_block(new Block("Order By", $order_html, "left", 15)); | ||||
| 
 | ||||
| 		$page->add_block(new Block("Pools", $html, "main", 10)); | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 		$this->display_paginator($page, "pool/list", null, $pageNumber, $totalPages); | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	/* | ||||
| 	 * HERE WE DISPLAY THE NEW POOL COMPOSER | ||||
| 	 */ | ||||
| @ -99,18 +121,31 @@ class PoolsTheme extends Themelet { | ||||
| 			</form> | ||||
| 		";
 | ||||
| 
 | ||||
| 		$blockTitle = "Create Pool"; | ||||
| 		$page->set_title(html_escape($blockTitle)); | ||||
| 		$page->set_heading(html_escape($blockTitle)); | ||||
| 		$this->display_top(null, "Create Pool"); | ||||
| 		$page->add_block(new Block("Create Pool", $create_html, "main", 20)); | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param array $pools | ||||
| 	 * @param string $heading | ||||
| 	 * @param bool $check_all | ||||
| 	 */ | ||||
| 	private function display_top(/*array*/ $pools, /*string*/ $heading, $check_all=false) { | ||||
| 		global $page, $user; | ||||
| 
 | ||||
| 		$page->set_title($heading); | ||||
| 		$page->set_heading($heading); | ||||
| 
 | ||||
| 		$nav_html = '<a href="'.make_link().'">Index</a>'; | ||||
| 		$poolnav_html = ' | ||||
| 			<a href="'.make_link("pool/list").'">Pool Index</a> | ||||
| 			<br><a href="'.make_link("pool/new").'">Create Pool</a> | ||||
| 			<br><a href="'.make_link("pool/updated").'">Pool Changes</a> | ||||
| 		'; | ||||
| 
 | ||||
| 		$page->add_block(new Block($nav_html, null, "left", 5)); | ||||
| 		$page->add_block(new Block("Pool Navigation", $poolnav_html, "left", 10)); | ||||
| 
 | ||||
| 		if(count($pools) == 1) { | ||||
| 			$pool = $pools[0]; | ||||
| 			if($pool['public'] == "Y" || $user->is_admin()) {// IF THE POOL IS PUBLIC OR IS ADMIN SHOW EDIT PANEL
 | ||||
| @ -122,36 +157,15 @@ class PoolsTheme extends Themelet { | ||||
| 			$bb = new BBCode(); | ||||
| 			$page->add_block(new Block(html_escape($pool['title']), $bb->format($pool['description']), "main", 10)); | ||||
| 		} | ||||
| 		else { | ||||
| 			$pool_info = ' | ||||
| 						<table id="poolsList" class="zebra"> | ||||
| 							<thead><tr> | ||||
| 								<th class="left">Title</th> | ||||
| 								<th class="left">Description</th> | ||||
| 							</tr></thead><tbody>'; | ||||
| 
 | ||||
| 			foreach($pools as $pool) { | ||||
| 				$pool_info .= "<tr>". | ||||
| 					"<td class='left'>".html_escape($pool['title'])."</td>". | ||||
| 					"<td class='left'>".html_escape($pool['description'])."</td>". | ||||
| 					"</tr>"; | ||||
| 
 | ||||
| 				// this will make disasters if more than one pool comes in the parameter
 | ||||
| 				if($pool['public'] == "Y" || $user->is_admin()) {// IF THE POOL IS PUBLIC OR IS ADMIN SHOW EDIT PANEL
 | ||||
| 					if(!$user->is_anonymous()) {// IF THE USER IS REGISTERED AND LOGGED IN SHOW EDIT PANEL
 | ||||
| 						$this->sidebar_options($page, $pool, $check_all); | ||||
| 					} | ||||
| 				} | ||||
| 	} | ||||
| 
 | ||||
| 			$pool_info .= "</tbody></table>"; | ||||
| 			$page->add_block(new Block($heading, $pool_info, "main", 10)); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	/* | ||||
| 	 * HERE WE DISPLAY THE POOL WITH TITLE DESCRIPTION AND IMAGES WITH PAGINATION | ||||
| 	/** | ||||
| 	 * HERE WE DISPLAY THE POOL WITH TITLE DESCRIPTION AND IMAGES WITH PAGINATION. | ||||
| 	 * | ||||
| 	 * @param array $pools | ||||
| 	 * @param array $images | ||||
| 	 * @param int $pageNumber | ||||
| 	 * @param int $totalPages | ||||
| 	 */ | ||||
| 	public function view_pool(/*array*/ $pools, /*array*/ $images, /*int*/ $pageNumber, /*int*/ $totalPages) { | ||||
| 		global $user, $page; | ||||
| @ -164,20 +178,17 @@ class PoolsTheme extends Themelet { | ||||
| 			$pool_images .= "\n".$thumb_html."\n"; | ||||
| 		} | ||||
| 
 | ||||
| 		$nav_html = ' | ||||
| 			<a href="'.make_link().'">Index</a> | ||||
| 			<br><a href="'.make_link("pool/new").'">Create Pool</a> | ||||
| 			<br><a href="'.make_link("pool/updated").'">Pool Changes</a> | ||||
| 		'; | ||||
| 
 | ||||
| 		$page->add_block(new Block("Navigation", $nav_html, "left", 10)); | ||||
| 		$page->add_block(new Block("Viewing Posts", $pool_images, "main", 30)); | ||||
| 		$this->display_paginator($page, "pool/view/".$pools[0]['id'], null, $pageNumber, $totalPages); | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	/* | ||||
| 	 * HERE WE DISPLAY THE POOL OPTIONS ON SIDEBAR BUT WE HIDE REMOVE OPTION IF THE USER IS NOT THE OWNER OR ADMIN | ||||
| 	/** | ||||
| 	 * HERE WE DISPLAY THE POOL OPTIONS ON SIDEBAR BUT WE HIDE REMOVE OPTION IF THE USER IS NOT THE OWNER OR ADMIN. | ||||
| 	 * | ||||
| 	 * @param Page $page | ||||
| 	 * @param array $pool | ||||
| 	 * @param bool $check_all | ||||
| 	 */ | ||||
| 	public function sidebar_options(Page $page, $pool, /*bool*/ $check_all) { | ||||
| 		global $user; | ||||
| @ -223,12 +234,7 @@ class PoolsTheme extends Themelet { | ||||
| 				<script language='javascript' type='text/javascript'> | ||||
| 				<!-- | ||||
| 				function setAll(value) { | ||||
| 					var a=new Array(); | ||||
| 					a=document.getElementsByName('check[]'); | ||||
| 					var p=0; | ||||
| 					for(i=0;i<a.length;i++){ | ||||
| 						a[i].checked = value; | ||||
| 					} | ||||
| 					$('[name=\"check[]\"]').attr('checked', value); | ||||
| 				} | ||||
| 				//-->
 | ||||
| 				</script> | ||||
| @ -236,27 +242,23 @@ class PoolsTheme extends Themelet { | ||||
| 				<input type='button' name='UnCheckAll' value='Uncheck All' onClick='setAll(false)'> | ||||
| 			";
 | ||||
| 		} | ||||
| 		$page->add_block(new Block("Manage Pool", $editor, "left", 10)); | ||||
| 		$page->add_block(new Block("Manage Pool", $editor, "left", 15)); | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	/* | ||||
| 	 * HERE WE DISPLAY THE RESULT OF THE SEARCH ON IMPORT | ||||
| 	/** | ||||
| 	 * HERE WE DISPLAY THE RESULT OF THE SEARCH ON IMPORT. | ||||
| 	 * | ||||
| 	 * @param Page $page | ||||
| 	 * @param array $images | ||||
| 	 * @param array $pool | ||||
| 	 */ | ||||
| 	public function pool_result(Page $page, /*array*/ $images, /*int*/ $pool_id) { | ||||
| 		// TODO: this could / should be done using jQuery
 | ||||
| 	public function pool_result(Page $page, /*array*/ $images, /*array*/ $pool) { | ||||
| 
 | ||||
| 		$this->display_top($pool, "Importing Posts", true); | ||||
| 		$pool_images = " | ||||
| 			<script language='javascript' type='text/javascript'> | ||||
| 			<!-- | ||||
| 			function setAll(value) { | ||||
| 				var a=new Array(); | ||||
| 				a=document.getElementsByName('check[]'); | ||||
| 				var p=0; | ||||
| 				for(i=0;i<a.length;i++) { | ||||
| 					a[i].checked = value; | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			function confirm_action() { | ||||
| 				return confirm('Are you sure you want to add selected posts to this pool?'); | ||||
| 			} | ||||
| @ -273,25 +275,23 @@ class PoolsTheme extends Themelet { | ||||
| 				'<input name="check[]" type="checkbox" value="'.$image->id.'" />'. | ||||
| 				'</span>'; | ||||
| 		} | ||||
| 
 | ||||
| 		$pool_images .= "<br>". | ||||
| 			"<input type='submit' name='edit' id='edit_pool_add_btn' value='Add Selected' onclick='return confirm_action()'/>". | ||||
| 			"<input type='hidden' name='pool_id' value='".$pool_id."'>". | ||||
| 			"<input type='hidden' name='pool_id' value='".$pool[0]['id']."'>". | ||||
| 			"</form>"; | ||||
| 
 | ||||
| 		$page->add_block(new Block("Import", $pool_images, "main", 10)); | ||||
| 
 | ||||
| 		$editor = " | ||||
| 			<input type='button' name='CheckAll' value='Check All' onClick='setAll(true)'> | ||||
| 			<input type='button' name='UnCheckAll' value='Uncheck All' onClick='setAll(false)'> | ||||
| 			";
 | ||||
| 
 | ||||
| 		$page->add_block(new Block("Manage Pool", $editor, "left", 10)); | ||||
| 		$page->add_block(new Block("Import", $pool_images, "main", 30)); | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	/* | ||||
| 	 * HERE WE DISPLAY THE POOL ORDERER | ||||
| 	/** | ||||
| 	 * HERE WE DISPLAY THE POOL ORDERER. | ||||
| 	 * WE LIST ALL IMAGES ON POOL WITHOUT PAGINATION AND WITH A TEXT INPUT TO SET A NUMBER AND CHANGE THE ORDER | ||||
| 	 * | ||||
| 	 * @param Page $page | ||||
| 	 * @param array $pools | ||||
| 	 * @param array $images | ||||
| 	 */ | ||||
| 	public function edit_order(Page $page, /*array*/ $pools, /*array*/ $images) { | ||||
| 		global $user; | ||||
| @ -318,16 +318,19 @@ class PoolsTheme extends Themelet { | ||||
| 		$page->add_block(new Block("Sorting Posts", $pool_images, "main", 30)); | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	/* | ||||
| 	 * HERE WE DISPLAY THE POOL EDITOR | ||||
| 	/** | ||||
| 	 * HERE WE DISPLAY THE POOL EDITOR. | ||||
| 	 * | ||||
| 	 * WE LIST ALL IMAGES ON POOL WITHOUT PAGINATION AND WITH | ||||
| 	 * A CHECKBOX TO SELECT WHICH IMAGE WE WANT TO REMOVE | ||||
| 	 * | ||||
| 	 * @param Page $page | ||||
| 	 * @param array $pools | ||||
| 	 * @param array $images | ||||
| 	 */ | ||||
| 	public function edit_pool(Page $page, /*array*/ $pools, /*array*/ $images) { | ||||
| 		global $user; | ||||
| 
 | ||||
| 
 | ||||
| 		/* EDIT POOL DESCRIPTION */ | ||||
| 		$desc_html = " | ||||
| 			".make_form(make_link("pool/edit_description"))." | ||||
| @ -362,8 +365,12 @@ class PoolsTheme extends Themelet { | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	/* | ||||
| 	 * HERE WE DISPLAY THE HISTORY LIST | ||||
| 	/** | ||||
| 	 * HERE WE DISPLAY THE HISTORY LIST. | ||||
| 	 * | ||||
| 	 * @param array $histories | ||||
| 	 * @param int $pageNumber | ||||
| 	 * @param int $totalPages | ||||
| 	 */ | ||||
| 	public function show_history($histories, /*int*/ $pageNumber, /*int*/ $totalPages) { | ||||
| 		global $page; | ||||
| @ -409,15 +416,7 @@ class PoolsTheme extends Themelet { | ||||
| 
 | ||||
| 		$html .= "</tbody></table>"; | ||||
| 
 | ||||
| 		$nav_html = ' | ||||
| 			<a href="'.make_link().'">Index</a> | ||||
| 			<br><a href="'.make_link("pool/new").'">Create Pool</a> | ||||
| 			<br><a href="'.make_link("pool/updated").'">Pool Changes</a> | ||||
| 		'; | ||||
| 
 | ||||
| 		$page->set_title("Recent Changes"); | ||||
| 		$page->set_heading("Recent Changes"); | ||||
| 		$page->add_block(new Block("Navigation", $nav_html, "left", 10)); | ||||
| 		$this->display_top(null, "Recent Changes"); | ||||
| 		$page->add_block(new Block("Recent Changes", $html, "main", 10)); | ||||
| 
 | ||||
| 		$this->display_paginator($page, "pool/updated", null, $pageNumber, $totalPages); | ||||
|  | ||||
| @ -1,9 +1,12 @@ | ||||
| <?php | ||||
| class QRImageTheme extends Themelet { | ||||
| 	/** | ||||
| 	 * @param string $link | ||||
| 	 */ | ||||
| 	public function links_block($link) { | ||||
| 		global $page; | ||||
| 		$page->add_block( new Block( | ||||
| 			"QR Code","<img alt='QR Code' src='http://chart.apis.google.com/chart?chs=150x150&cht=qr&chl=$link' />","left",50)); | ||||
| 			"QR Code","<img alt='QR Code' src='http://chart.apis.google.com/chart?chs=150x150&cht=qr&chl={$link}' />","left",50)); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -22,7 +22,8 @@ | ||||
| 
 | ||||
| class RandomImage extends Extension { | ||||
| 	public function onPageRequest(PageRequestEvent $event) { | ||||
| 		global $config, $database, $page, $user; | ||||
| 		global $page; | ||||
| 
 | ||||
| 		if($event->page_matches("random_image")) { | ||||
| 			$action = ''; | ||||
| 			if($event->count_args() == 1) { | ||||
| @ -34,7 +35,7 @@ class RandomImage extends Extension { | ||||
| 				$search_terms = explode(' ', $event->get_arg(1)); | ||||
| 			} | ||||
| 			else { | ||||
| 				# FIXME: throw exception
 | ||||
| 				throw new SCoreException("Error: too many arguments."); | ||||
| 			} | ||||
| 			$image = Image::by_random($search_terms); | ||||
| 
 | ||||
|  | ||||
| @ -1,12 +1,24 @@ | ||||
| <?php | ||||
| 
 | ||||
| class RandomImageTheme extends Themelet { | ||||
| 	public function display_random(Page $page, Image $image) { | ||||
| class RandomImageTheme extends Themelet | ||||
| { | ||||
| 	/** | ||||
| 	 * @param Page $page | ||||
| 	 * @param Image $image | ||||
| 	 */ | ||||
| 	public function display_random(Page $page, Image $image) | ||||
| 	{ | ||||
| 		$page->add_block(new Block("Random Image", $this->build_random_html($image), "left", 8)); | ||||
| 	} | ||||
| 
 | ||||
| 		public function build_random_html(Image $image, $query=null) { | ||||
| 		global $config; | ||||
| 	/** | ||||
| 	 * @param Image $image | ||||
| 	 * @param null|string $query | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	public function build_random_html(Image $image, $query = null) | ||||
| 	{ | ||||
| 
 | ||||
| 		$i_id = int_escape($image->id); | ||||
| 		$h_view_link = make_link("post/view/$i_id", $query); | ||||
| 		$h_thumb_link = $image->get_thumb_link(); | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| <?php | ||||
| /* needed for access to build_thumb_html */ | ||||
| class RandomListTheme extends Themelet {} | ||||
| ?>
 | ||||
| 
 | ||||
|  | ||||
| @ -20,10 +20,18 @@ | ||||
|  */ | ||||
| 
 | ||||
| class RatingSetEvent extends Event { | ||||
| 	var $image, $rating; | ||||
| 	/** @var \Image */ | ||||
| 	public $image; | ||||
| 	/** @var string  */ | ||||
| 	public $rating; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param Image $image | ||||
| 	 * @param string $rating | ||||
| 	 */ | ||||
| 	public function __construct(Image $image, /*char*/ $rating) { | ||||
| 		assert(in_array($rating, array("s", "q", "e", "u"))); | ||||
| 
 | ||||
| 		$this->image = $image; | ||||
| 		$this->rating = $rating; | ||||
| 	} | ||||
| @ -31,6 +39,9 @@ class RatingSetEvent extends Event { | ||||
| 
 | ||||
| class Ratings extends Extension { | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @return int | ||||
| 	 */ | ||||
| 	public function get_priority() {return 50;} | ||||
| 
 | ||||
| 	public function onInitExt(InitExtEvent $event) { | ||||
| @ -69,7 +80,7 @@ class Ratings extends Extension { | ||||
| 
 | ||||
| 	 | ||||
| 	public function onDisplayingImage(DisplayingImageEvent $event) { | ||||
| 		global $user, $database, $page; | ||||
| 		global $user, $page; | ||||
| 		/** | ||||
| 		 * Deny images upon insufficient permissions. | ||||
| 		 **/ | ||||
| @ -97,15 +108,13 @@ class Ratings extends Extension { | ||||
| 	} | ||||
| 	 | ||||
| 	public function onImageInfoSet(ImageInfoSetEvent $event) { | ||||
| 		global $user; | ||||
| 		 | ||||
| 		if($this->can_rate() && isset($_POST["rating"])) { | ||||
| 			send_event(new RatingSetEvent($event->image, $_POST['rating'])); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	public function onParseLinkTemplate(ParseLinkTemplateEvent $event) { | ||||
| 		$event->replace('$rating', $this->theme->rating_to_name($event->image->rating)); | ||||
| 		$event->replace('$rating', $this->rating_to_human($event->image->rating)); | ||||
| 	} | ||||
| 
 | ||||
| 	public function onSearchTermParse(SearchTermParseEvent $event) { | ||||
| @ -125,11 +134,11 @@ class Ratings extends Extension { | ||||
| 	} | ||||
| 
 | ||||
| 	public function onPageRequest(PageRequestEvent $event) { | ||||
| 		global $database, $user, $page; | ||||
| 		global $user, $page; | ||||
| 		 | ||||
| 		if ($event->page_matches("admin/bulk_rate")) { | ||||
| 			if(!$user->is_admin()) { | ||||
| 				throw PermissionDeniedException(); | ||||
| 				throw new PermissionDeniedException(); | ||||
| 			} | ||||
| 			else { | ||||
| 				$n = 0; | ||||
| @ -155,8 +164,13 @@ class Ratings extends Extension { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	public static function get_user_privs($user) { | ||||
| 	/** | ||||
| 	 * @param \User $user | ||||
| 	 * @return null|string | ||||
| 	 */ | ||||
| 	public static function get_user_privs(User $user) { | ||||
| 		global $config; | ||||
| 
 | ||||
| 		if($user->is_anonymous()) { | ||||
| 			$sqes = $config->get_string("ext_rating_anon_privs"); | ||||
| 		} | ||||
| @ -169,6 +183,10 @@ class Ratings extends Extension { | ||||
| 		return $sqes; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $sqes | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	public static function privs_to_sql(/*string*/ $sqes) { | ||||
| 		$arr = array(); | ||||
| 		$length = strlen($sqes); | ||||
| @ -179,6 +197,10 @@ class Ratings extends Extension { | ||||
| 		return $set; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $rating | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	public static function rating_to_human(/*string*/ $rating) { | ||||
| 		switch($rating) { | ||||
| 			case "s": return "Safe"; | ||||
| @ -188,7 +210,11 @@ class Ratings extends Extension { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// FIXME: this is a bit ugly and guessey, should have proper options
 | ||||
| 	/** | ||||
| 	 * FIXME: this is a bit ugly and guessey, should have proper options | ||||
| 	 * | ||||
| 	 * @return bool | ||||
| 	 */ | ||||
| 	private function can_rate() { | ||||
| 		global $config, $user; | ||||
| 		if($user->is_anonymous() && $config->get_string("ext_rating_anon_privs") == "sqeu") return false; | ||||
| @ -197,6 +223,10 @@ class Ratings extends Extension { | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param $context | ||||
| 	 * @return bool | ||||
| 	 */ | ||||
| 	private function no_rating_query($context) { | ||||
| 		foreach($context as $term) { | ||||
| 			if(preg_match("/^rating[=|:]/", $term)) { | ||||
| @ -207,8 +237,7 @@ class Ratings extends Extension { | ||||
| 	} | ||||
| 
 | ||||
| 	private function install() { | ||||
| 		global $database; | ||||
| 		global $config; | ||||
| 		global $database, $config; | ||||
| 
 | ||||
| 		if($config->get_int("ext_ratings2_version") < 1) { | ||||
| 			$database->Execute("ALTER TABLE images ADD COLUMN rating CHAR(1) NOT NULL DEFAULT 'u'"); | ||||
| @ -227,11 +256,16 @@ class Ratings extends Extension { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param int $image_id | ||||
| 	 * @param string $rating | ||||
| 	 * @param string $old_rating | ||||
| 	 */ | ||||
| 	private function set_rating(/*int*/ $image_id, /*string*/ $rating, /*string*/ $old_rating) { | ||||
| 		global $database; | ||||
| 		if($old_rating != $rating){ | ||||
| 			$database->Execute("UPDATE images SET rating=? WHERE id=?", array($rating, $image_id)); | ||||
| 			log_info("rating", "Rating for Image #{$image_id} set to: ".$this->theme->rating_to_name($rating)); | ||||
| 			log_info("rating", "Rating for Image #{$image_id} set to: ".$this->rating_to_human($rating)); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -1,6 +1,11 @@ | ||||
| <?php | ||||
| 
 | ||||
| class RatingsTheme extends Themelet { | ||||
| 	/** | ||||
| 	 * @param int $image_id | ||||
| 	 * @param string $rating | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	public function get_rater_html(/*int*/ $image_id, /*string*/ $rating) { | ||||
| 		$s_checked = $rating == 's' ? " checked" : ""; | ||||
| 		$q_checked = $rating == 'q' ? " checked" : ""; | ||||
| @ -34,15 +39,6 @@ class RatingsTheme extends Themelet { | ||||
| 		";
 | ||||
| 		$page->add_block(new Block("List Controls", $html, "left")); | ||||
| 	} | ||||
| 
 | ||||
| 	public function rating_to_name(/*string*/ $rating) { | ||||
| 		switch($rating) { | ||||
| 			case 's': return "Safe"; | ||||
| 			case 'q': return "Questionable"; | ||||
| 			case 'e': return "Explicit"; | ||||
| 			default: return "Unknown"; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
| @ -15,7 +15,7 @@ | ||||
| 
 | ||||
| class RegenThumb extends Extension { | ||||
| 	public function onPageRequest(PageRequestEvent $event) { | ||||
| 		global $config, $database, $page, $user; | ||||
| 		global $page, $user; | ||||
| 
 | ||||
| 		if($event->page_matches("regen_thumb") && $user->can("delete_image") && isset($_POST['image_id'])) { | ||||
| 			$image = Image::by_id(int_escape($_POST['image_id'])); | ||||
|  | ||||
| @ -1,8 +1,11 @@ | ||||
| <?php | ||||
| 
 | ||||
| class RegenThumbTheme extends Themelet { | ||||
| 	/* | ||||
| 	/** | ||||
| 	 * Show a form which offers to regenerate the thumb of an image with ID #$image_id
 | ||||
| 	 * | ||||
| 	 * @param int|string $image_id | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	public function get_buttons_html($image_id) { | ||||
| 		return " | ||||
| @ -13,8 +16,11 @@ class RegenThumbTheme extends Themelet { | ||||
| 		";
 | ||||
| 	} | ||||
| 
 | ||||
| 	/* | ||||
| 	 * Show a link to the new thumbnail | ||||
| 	/** | ||||
| 	 * Show a link to the new thumbnail. | ||||
| 	 * | ||||
| 	 * @param Page $page | ||||
| 	 * @param Image $image | ||||
| 	 */ | ||||
| 	public function display_results(Page $page, Image $image) { | ||||
| 		$page->set_title("Thumbnail Regenerated"); | ||||
|  | ||||
| @ -21,7 +21,6 @@ class Relationships extends Extension { | ||||
| 	} | ||||
| 
 | ||||
| 	public function onImageInfoSet(ImageInfoSetEvent $event) { | ||||
|         global $user; | ||||
| 		if(isset($_POST['tag_edit__tags']) ? !preg_match('/parent[=|:]/', $_POST["tag_edit__tags"]) : TRUE) { //Ignore tag_edit__parent if tags contain parent metatag
 | ||||
| 			if (isset($_POST["tag_edit__parent"]) ? ctype_digit($_POST["tag_edit__parent"]) : FALSE) { | ||||
| 				$this->set_parent($event->image->id, (int) $_POST["tag_edit__parent"]); | ||||
| @ -91,6 +90,10 @@ class Relationships extends Extension { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param int $imageID | ||||
| 	 * @param int $parentID | ||||
| 	 */ | ||||
| 	private function set_parent(/*int*/ $imageID, /*int*/ $parentID){ | ||||
| 		global $database; | ||||
| 
 | ||||
| @ -100,6 +103,10 @@ class Relationships extends Extension { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param int $parentID | ||||
| 	 * @param int $childID | ||||
| 	 */ | ||||
| 	private function set_child(/*int*/ $parentID, /*int*/ $childID){ | ||||
| 		global $database; | ||||
| 
 | ||||
| @ -109,6 +116,9 @@ class Relationships extends Extension { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param int $imageID | ||||
| 	 */ | ||||
| 	private function remove_parent(/*int*/ $imageID){ | ||||
| 		global $database; | ||||
| 		$parentID = $database->get_one("SELECT parent_id FROM images WHERE id = :iid", array("iid"=>$imageID)); | ||||
|  | ||||
| @ -1,6 +1,9 @@ | ||||
| <?php | ||||
| 
 | ||||
| class RelationshipsTheme extends Themelet { | ||||
| 	/** | ||||
| 	 * @param \Image $image | ||||
| 	 */ | ||||
| 	public function relationship_info($image) { | ||||
| 		global $page, $database; | ||||
| 
 | ||||
| @ -25,6 +28,7 @@ class RelationshipsTheme extends Themelet { | ||||
| 
 | ||||
| 	public function get_parent_editor_html(Image $image) { | ||||
| 		global $user; | ||||
| 
 | ||||
| 		$h_parent_id = $image->parent_id; | ||||
| 		$s_parent_id = $h_parent_id ?: "None."; | ||||
| 
 | ||||
|  | ||||
| @ -10,18 +10,30 @@ | ||||
|  */ | ||||
| 
 | ||||
| class RemoveReportedImageEvent extends Event { | ||||
| 	var $id; | ||||
| 	/** @var  int */ | ||||
| 	public $id; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param int $id | ||||
| 	 */ | ||||
| 	public function __construct($id) { | ||||
| 		$this->id = $id; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| class AddReportedImageEvent extends Event { | ||||
| 	var $reporter_id; | ||||
| 	var $image_id; | ||||
| 	var $reason; | ||||
| 	/** @var int  */ | ||||
| 	public $reporter_id; | ||||
| 	/** @var int  */ | ||||
| 	public $image_id; | ||||
| 	/** @var string  */ | ||||
| 	public $reason; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param int $image_id | ||||
| 	 * @param int $reporter_id | ||||
| 	 * @param string $reason | ||||
| 	 */ | ||||
| 	public function __construct($image_id, $reporter_id, $reason) { | ||||
| 		$this->reporter_id = $reporter_id; | ||||
| 		$this->image_id = $image_id; | ||||
| @ -89,7 +101,7 @@ class ReportImage extends Extension { | ||||
| 	} | ||||
| 
 | ||||
| 	public function onDisplayingImage(DisplayingImageEvent $event) { | ||||
| 		global $config, $user, $page; | ||||
| 		global $user, $page; | ||||
| 		if($user->can('create_image_report')) { | ||||
| 			$reps = $this->get_reporters($event->image); | ||||
| 			$this->theme->display_image_banner($event->image, $reps); | ||||
| @ -112,8 +124,8 @@ class ReportImage extends Extension { | ||||
| 	} | ||||
| 
 | ||||
| 	protected function install() { | ||||
| 		global $database; | ||||
| 		global $config; | ||||
| 		global $database, $config; | ||||
| 
 | ||||
| 		if($config->get_int("ext_report_image_version") < 1) { | ||||
| 			$database->create_table("image_reports", " | ||||
| 				id SCORE_AIPK, | ||||
| @ -127,8 +139,13 @@ class ReportImage extends Extension { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param Image $image | ||||
| 	 * @return array | ||||
| 	 */ | ||||
| 	public function get_reporters(Image $image) { | ||||
| 		global $database; | ||||
| 
 | ||||
| 		return $database->get_col(" | ||||
| 			SELECT users.name | ||||
| 			FROM image_reports | ||||
| @ -137,8 +154,12 @@ class ReportImage extends Extension { | ||||
| 		", array("image_id" => $image->id));
 | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @return array | ||||
| 	 */ | ||||
| 	public function get_reported_images() { | ||||
| 		global $config, $database; | ||||
| 		global $database; | ||||
| 
 | ||||
| 		$all_reports = $database->get_all(" | ||||
| 			SELECT image_reports.*, users.name AS reporter_name | ||||
| 			FROM image_reports | ||||
| @ -160,6 +181,9 @@ class ReportImage extends Extension { | ||||
| 		return $reports; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @return mixed | ||||
| 	 */ | ||||
| 	public function count_reported_images() { | ||||
| 		global $database; | ||||
| 
 | ||||
|  | ||||
| @ -11,6 +11,10 @@ | ||||
|  */ | ||||
| 
 | ||||
| class ReportImageTheme extends Themelet { | ||||
| 	/** | ||||
| 	 * @param Page $page | ||||
| 	 * @param array $reports | ||||
| 	 */ | ||||
| 	public function display_reported_images(Page $page, $reports) { | ||||
| 		global $config; | ||||
| 
 | ||||
| @ -57,11 +61,14 @@ class ReportImageTheme extends Themelet { | ||||
| 		$page->set_heading("Reported Images"); | ||||
| 		$page->add_block(new NavBlock()); | ||||
| 		$page->add_block(new Block("Reported Images", $html)); | ||||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param Image $image | ||||
| 	 * @param array $reporters | ||||
| 	 */ | ||||
| 	public function display_image_banner(Image $image, /*array*/ $reporters) { | ||||
| 		global $config, $page; | ||||
| 		global $page; | ||||
| 
 | ||||
| 		$i_image = int_escape($image->id); | ||||
| 		$html = ""; | ||||
|  | ||||
| @ -154,9 +154,14 @@ class ResizeImage extends Extension { | ||||
| 	// Private functions
 | ||||
| 	/* ----------------------------- */ | ||||
| 
 | ||||
| 	/* | ||||
| 		This function could be made much smaller by using the ImageReplaceEvent | ||||
| 		ie: Pretend that we are replacing the image with a resized copy. | ||||
| 	/** | ||||
| 	 * This function could be made much smaller by using the ImageReplaceEvent | ||||
| 	 * ie: Pretend that we are replacing the image with a resized copy. | ||||
| 	 * | ||||
| 	 * @param Image $image_obj | ||||
| 	 * @param int $width | ||||
| 	 * @param int $height | ||||
| 	 * @throws ImageResizeException | ||||
| 	 */ | ||||
| 	private function resize_image(Image $image_obj, /*int*/ $width, /*int*/ $height) { | ||||
| 		global $config, $user, $page, $database; | ||||
|  | ||||
| @ -16,8 +16,12 @@ | ||||
|  * This class is just a wrapper around SCoreException. | ||||
|  */ | ||||
| class ImageRotateException extends SCoreException { | ||||
| 	var $error; | ||||
| 	/** @var string */ | ||||
| 	public $error; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $error | ||||
| 	 */ | ||||
| 	public function __construct($error) { | ||||
| 		$this->error = $error; | ||||
| 	} | ||||
| @ -101,9 +105,13 @@ class RotateImage extends Extension { | ||||
| 	// Private functions
 | ||||
| 	/* ----------------------------- */ | ||||
| 
 | ||||
| 	/* | ||||
| 		This function could be made much smaller by using the ImageReplaceEvent | ||||
| 		ie: Pretend that we are replacing the image with a rotated copy. | ||||
| 	/** | ||||
| 	 * This function could be made much smaller by using the ImageReplaceEvent | ||||
| 	 * ie: Pretend that we are replacing the image with a rotated copy. | ||||
| 	 * | ||||
| 	 * @param int $image_id | ||||
| 	 * @param int $deg | ||||
| 	 * @throws ImageRotateException | ||||
| 	 */ | ||||
| 	private function rotate_image(/*int*/ $image_id, /*int*/ $deg) { | ||||
| 		global $config, $user, $page, $database; | ||||
|  | ||||
| @ -1,12 +1,13 @@ | ||||
| <?php | ||||
| 
 | ||||
| class RotateImageTheme extends Themelet { | ||||
| 	/* | ||||
| 	 * Display a link to rotate an image | ||||
| 	/** | ||||
| 	 * Display a link to rotate an image. | ||||
| 	 * | ||||
| 	 * @param int $image_id | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	public function get_rotate_html(/*int*/ $image_id) { | ||||
| 		global $user, $config; | ||||
| 
 | ||||
| 		$html = " | ||||
| 			".make_form(make_link('rotate/'.$image_id), 'POST')." | ||||
| 				<input type='hidden' name='image_id' value='$image_id'> | ||||
| @ -18,6 +19,13 @@ class RotateImageTheme extends Themelet { | ||||
| 		return $html; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Display the error. | ||||
| 	 * | ||||
| 	 * @param Page $page | ||||
| 	 * @param string $title | ||||
| 	 * @param string $message | ||||
| 	 */ | ||||
| 	public function display_rotate_error(Page $page, /*string*/ $title, /*string*/ $message) { | ||||
| 		$page->set_title("Rotate Image"); | ||||
| 		$page->set_heading("Rotate Image"); | ||||
|  | ||||
| @ -33,6 +33,11 @@ class RSS_Images extends Extension { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param array $images | ||||
| 	 * @param array $search_terms | ||||
| 	 * @param int $page_number | ||||
| 	 */ | ||||
| 	private function do_rss($images, $search_terms, /*int*/ $page_number) { | ||||
| 		global $page; | ||||
| 		global $config; | ||||
| @ -78,6 +83,10 @@ class RSS_Images extends Extension { | ||||
| 		$page->set_data($xml); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param Image $image | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	private function thumb(Image $image) { | ||||
| 		global $database; | ||||
| 
 | ||||
|  | ||||
| @ -12,8 +12,12 @@ | ||||
|  * activated; new config options are in $_POST | ||||
|  */ | ||||
| class ConfigSaveEvent extends Event { | ||||
| 	var $config; | ||||
| 	/** @var \Config */ | ||||
| 	public $config; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param Config $config | ||||
| 	 */ | ||||
| 	public function __construct(Config $config) { | ||||
| 		$this->config = $config; | ||||
| 	} | ||||
| @ -24,8 +28,12 @@ class ConfigSaveEvent extends Event { | ||||
|  * Sent when the setup page is ready to be added to | ||||
|  */ | ||||
| class SetupBuildingEvent extends Event { | ||||
| 	var $panel; | ||||
| 	/** @var \SetupPanel */ | ||||
| 	public $panel; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param SetupPanel $panel | ||||
| 	 */ | ||||
| 	public function __construct(SetupPanel $panel) { | ||||
| 		$this->panel = $panel; | ||||
| 	} | ||||
| @ -35,8 +43,12 @@ class SetupBuildingEvent extends Event { | ||||
|  * | ||||
|  */ | ||||
| class SetupPanel { | ||||
| 	var $blocks = array(); | ||||
| 	/** @var \SetupBlock[]  */ | ||||
| 	public $blocks = array(); | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param SetupBlock $block | ||||
| 	 */ | ||||
| 	public function add_block(SetupBlock $block) { | ||||
| 		$this->blocks[] = $block; | ||||
| 	} | ||||
| @ -46,9 +58,14 @@ class SetupPanel { | ||||
|  * | ||||
|  */ | ||||
| class SetupBlock extends Block { | ||||
| 	var $header; | ||||
| 	var $body; | ||||
| 	/** @var string  */ | ||||
| 	public $header; | ||||
| 	/** @var string  */ | ||||
| 	public $body; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $title | ||||
| 	 */ | ||||
| 	public function __construct($title) { | ||||
| 		$this->header = $title; | ||||
| 		$this->section = "main"; | ||||
| @ -56,20 +73,31 @@ class SetupBlock extends Block { | ||||
| 		$this->body = ""; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $text | ||||
| 	 */ | ||||
| 	public function add_label($text) { | ||||
| 		$this->body .= $text; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $name | ||||
| 	 * @param null|string $label | ||||
| 	 */ | ||||
| 	public function add_text_option($name, $label=null) { | ||||
| 		global $config; | ||||
| 		$val = html_escape($config->get_string($name)); | ||||
| 		if(!is_null($label)) { | ||||
| 			$this->body .= "<label for='$name'>$label</label>"; | ||||
| 			$this->body .= "<label for='{$name}'>{$label}</label>"; | ||||
| 		} | ||||
| 		$this->body .= "<input type='text' id='$name' name='_config_$name' value='$val'>\n"; | ||||
| 		$this->body .= "<input type='hidden' name='_type_$name' value='string'>\n"; | ||||
| 		$this->body .= "<input type='text' id='{$name}' name='_config_{$name}' value='{$val}'>\n"; | ||||
| 		$this->body .= "<input type='hidden' name='_type_{$name}' value='string'>\n"; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $name | ||||
| 	 * @param null|string $label | ||||
| 	 */ | ||||
| 	public function add_longtext_option($name, $label=null) { | ||||
| 		global $config; | ||||
| 		$val = html_escape($config->get_string($name)); | ||||
| @ -81,6 +109,10 @@ class SetupBlock extends Block { | ||||
| 		$this->body .= "<input type='hidden' name='_type_$name' value='string'>\n"; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $name | ||||
| 	 * @param null|string $label | ||||
| 	 */ | ||||
| 	public function add_bool_option($name, $label=null) { | ||||
| 		global $config; | ||||
| 		$checked = $config->get_bool($name) ? " checked" : ""; | ||||
| @ -97,6 +129,10 @@ class SetupBlock extends Block { | ||||
| //		$this->body .= "<input type='hidden' id='$name' name='$name' value='$val'>";
 | ||||
| //	}
 | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $name | ||||
| 	 * @param null|string $label | ||||
| 	 */ | ||||
| 	public function add_int_option($name, $label=null) { | ||||
| 		global $config; | ||||
| 		$val = html_escape($config->get_string($name)); | ||||
| @ -107,6 +143,10 @@ class SetupBlock extends Block { | ||||
| 		$this->body .= "<input type='hidden' name='_type_$name' value='int'>\n"; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $name | ||||
| 	 * @param null|string $label | ||||
| 	 */ | ||||
| 	public function add_shorthand_int_option($name, $label=null) { | ||||
| 		global $config; | ||||
| 		$val = to_shorthand_int($config->get_string($name)); | ||||
|  | ||||
| @ -42,7 +42,7 @@ class _SafeImage { | ||||
| 		$this->posted   = $img->posted_timestamp; | ||||
| 		$this->source   = $img->source; | ||||
| 		$this->owner_id = $img->owner_id; | ||||
| 		$this->tags     = $img->tag_array; | ||||
| 		$this->tags     = $img->get_tag_array(); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -19,7 +19,7 @@ | ||||
|  * For Shimmie2 specific extensions, there is a ShimmieWebTestCase class which | ||||
|  * includes functions to upload and delete images. | ||||
|  * | ||||
|  * For a quick guide on the spcifics of how to write tests, see \ref wut | ||||
|  * For a quick guide on the specifics of how to write tests, see \ref wut | ||||
|  * | ||||
|  * | ||||
|  * \page wut Writing Unit Tests | ||||
| @ -88,19 +88,24 @@ define('ADMIN_NAME', "demo"); | ||||
| define('ADMIN_PASS', "demo"); | ||||
| 
 | ||||
| /** | ||||
|  * A set of common SCore activities to test | ||||
|  * Class SCoreWebTestCase | ||||
|  * | ||||
|  * A set of common SCore activities to test. | ||||
|  */ | ||||
| class SCoreWebTestCase extends WebTestCase { | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Click on a link or a button | ||||
| 	 * Click on a link or a button. | ||||
| 	 * @param string $text | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	public function click($text) { | ||||
| 		return parent::click($text); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Click the virtual browser's back button | ||||
| 	 * Click the virtual browser's back button. | ||||
| 	 * @return bool | ||||
| 	 */ | ||||
| 	public function back() { | ||||
| 		return parent::back(); | ||||
| @ -165,9 +170,16 @@ class SCoreWebTestCase extends WebTestCase { | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * A set of common Shimmie activities to test | ||||
|  * Class ShimmieWebTestCase | ||||
|  * | ||||
|  * A set of common Shimmie activities to test. | ||||
|  */ | ||||
| class ShimmieWebTestCase extends SCoreWebTestCase { | ||||
| 	/** | ||||
| 	 * @param string $filename | ||||
| 	 * @param string|string[] $tags | ||||
| 	 * @return int | ||||
| 	 */ | ||||
| 	protected function post_image($filename, $tags) { | ||||
| 		$image_id = -1; | ||||
| 		$this->setMaximumRedirects(0); | ||||
| @ -195,6 +207,9 @@ class ShimmieWebTestCase extends SCoreWebTestCase { | ||||
| 		return $image_id; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param int $image_id | ||||
| 	 */ | ||||
| 	protected function delete_image($image_id) { | ||||
| 		if($image_id > 0) { | ||||
| 	        $this->get_page('post/view/'.$image_id); | ||||
|  | ||||
| @ -1,4 +1,5 @@ | ||||
| <?php | ||||
| 
 | ||||
| /* | ||||
|  * Name: XML Sitemap | ||||
|  * Author: Sein Kraft <mail@seinkraft.info> | ||||
| @ -9,30 +10,31 @@ | ||||
|  * Documentation: | ||||
|  */ | ||||
| 
 | ||||
| class XMLSitemap extends Extension { | ||||
| class XMLSitemap extends Extension | ||||
| { | ||||
| 	private $sitemap_queue = ""; | ||||
| 	private $sitemap_filepath = ""; // set onPageRequest
 | ||||
| 
 | ||||
| 	public function onPageRequest(PageRequestEvent $event) {  | ||||
|             if($event->page_matches("sitemap.xml"))  | ||||
| 	public function onPageRequest(PageRequestEvent $event) | ||||
| 	{ | ||||
| 		if ($event->page_matches("sitemap.xml")) { | ||||
| 			global $config; | ||||
| 
 | ||||
|                 $this->sitemap_filepath = $_SERVER['DOCUMENT_ROOT']."/data/cache/sitemap.xml"; | ||||
| 			$this->sitemap_filepath = $_SERVER['DOCUMENT_ROOT'] . "/data/cache/sitemap.xml"; | ||||
| 			// determine if new sitemap needs to be generated
 | ||||
|                 if ($this->new_sitemap_needed()) | ||||
|                 { | ||||
| 			if ($this->new_sitemap_needed()) { | ||||
| 				// determine which type of sitemap to generate
 | ||||
|                     if ($config->get_bool("sitemap_generatefull",false)) | ||||
| 				if ($config->get_bool("sitemap_generatefull", false)) { | ||||
| 					$this->handle_full_sitemap(); // default false until cache fixed
 | ||||
|                     else | ||||
| 				} else { | ||||
| 					$this->handle_smaller_sitemap(); | ||||
| 				} | ||||
|                 else $this->display_existing_sitemap(); | ||||
| 			} else $this->display_existing_sitemap(); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|         public function onSetupBuilding(SetupBuildingEvent $event) { | ||||
| 	public function onSetupBuilding(SetupBuildingEvent $event) | ||||
| 	{ | ||||
| 		$sb = new SetupBlock("Sitemap"); | ||||
| 
 | ||||
| 		$sb->add_bool_option("sitemap_generatefull", "Generate full sitemap"); | ||||
| @ -48,9 +50,11 @@ class XMLSitemap extends Extension { | ||||
| 		/* --- Add latest images to sitemap with higher priority --- */ | ||||
| 		$latestimages = Image::find_images(0, 50, array()); | ||||
| 		$latestimages_urllist = array(); | ||||
|                 foreach($latestimages as $arrayid => $image) | ||||
| 		foreach ($latestimages as $arrayid => $image) { | ||||
| 			// create url from image id's
 | ||||
| 			$latestimages_urllist[$arrayid] = "post/view/$image->id"; | ||||
| 		} | ||||
| 
 | ||||
| 		$this->add_sitemap_queue($latestimages_urllist, "monthly", "0.8", date("Y-m-d", $image->posted_timestamp)); | ||||
| 
 | ||||
| 		/* --- Display page --- */ | ||||
| @ -70,7 +74,7 @@ class XMLSitemap extends Extension { | ||||
| 
 | ||||
| 		/* --- Add 20 most used tags --- */ | ||||
| 		$popular_tags = $database->get_all("SELECT tag, count FROM tags ORDER BY `count` DESC LIMIT 0,20"); | ||||
|                 foreach($popular_tags as $arrayid => $tag) { | ||||
| 		foreach ($popular_tags as $arrayid => $tag) { | ||||
| 			$tag = $tag['tag']; | ||||
| 			$popular_tags[$arrayid] = "post/list/$tag/"; | ||||
| 		} | ||||
| @ -79,14 +83,15 @@ class XMLSitemap extends Extension { | ||||
| 		/* --- Add latest images to sitemap with higher priority --- */ | ||||
| 		$latestimages = Image::find_images(0, 50, array()); | ||||
| 		$latestimages_urllist = array(); | ||||
|                 foreach($latestimages as $arrayid => $image) | ||||
| 		foreach ($latestimages as $arrayid => $image) { | ||||
| 			// create url from image id's
 | ||||
| 			$latestimages_urllist[$arrayid] = "post/view/$image->id"; | ||||
| 		} | ||||
| 		$this->add_sitemap_queue($latestimages_urllist, "monthly", "0.8", date("Y-m-d", $image->posted_timestamp)); | ||||
| 
 | ||||
| 		/* --- Add other tags --- */ | ||||
| 		$other_tags = $database->get_all("SELECT tag, count FROM tags ORDER BY `count` DESC LIMIT 21,10000000"); | ||||
|                 foreach($other_tags as $arrayid => $tag) { | ||||
| 		foreach ($other_tags as $arrayid => $tag) { | ||||
| 			$tag = $tag['tag']; | ||||
| 			// create url from tags (tagme ignored)
 | ||||
| 			if ($tag != "tagme") | ||||
| @ -96,9 +101,10 @@ class XMLSitemap extends Extension { | ||||
| 
 | ||||
| 		/* --- Add all other images to sitemap with lower priority --- */ | ||||
| 		$otherimages = Image::find_images(51, 10000000, array()); | ||||
|                 foreach($otherimages as $arrayid => $image) | ||||
| 		foreach ($otherimages as $arrayid => $image) { | ||||
| 			// create url from image id's
 | ||||
| 			$otherimages[$arrayid] = "post/view/$image->id"; | ||||
| 		} | ||||
| 		$this->add_sitemap_queue($otherimages, "monthly", "0.6", date("Y-m-d", $image->posted_timestamp)); | ||||
| 
 | ||||
| 
 | ||||
| @ -107,9 +113,18 @@ class XMLSitemap extends Extension { | ||||
| 		$this->generate_display_sitemap(); | ||||
| 	} | ||||
| 
 | ||||
|         // Adds an array of urls to the sitemap with the given information
 | ||||
| 	private function add_sitemap_queue(/*array(urls)*/ $urls, $changefreq="monthly", $priority="0.5", $date="2013-02-01") { | ||||
|                 foreach($urls as $url) { | ||||
| 	/** | ||||
| 	 * Adds an array of urls to the sitemap with the given information. | ||||
| 	 * | ||||
| 	 * @param array $urls | ||||
| 	 * @param string $changefreq | ||||
| 	 * @param string $priority | ||||
| 	 * @param string $date | ||||
| 	 */ | ||||
| 	private function add_sitemap_queue( /*array(urls)*/ $urls, $changefreq = "monthly", | ||||
| 										$priority = "0.5", $date = "2013-02-01") | ||||
| 	{ | ||||
| 		foreach ($urls as $url) { | ||||
| 			$link = make_http(make_link("$url")); | ||||
| 			$this->sitemap_queue .= " | ||||
|                     <url> | ||||
| @ -126,7 +141,7 @@ class XMLSitemap extends Extension { | ||||
| 	{ | ||||
| 		global $page; | ||||
| 
 | ||||
|             $xml = "<"."?xml version=\"1.0\" encoding=\"utf-8\"?".">
 | ||||
| 		$xml = "<" . "?xml version=\"1.0\" encoding=\"utf-8\"?" . ">
 | ||||
| 				<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">
 | ||||
| 					$this->sitemap_queue | ||||
| 				</urlset>";
 | ||||
| @ -138,19 +153,27 @@ class XMLSitemap extends Extension { | ||||
| 		$page->set_data($xml); | ||||
| 	} | ||||
| 
 | ||||
|         // returns true if a new sitemap is needed
 | ||||
| 	/** | ||||
| 	 * Returns true if a new sitemap is needed. | ||||
| 	 * | ||||
| 	 * @return bool | ||||
| 	 */ | ||||
| 	private function new_sitemap_needed() | ||||
| 	{ | ||||
| 		$sitemap_generation_interval = 86400; // allow new site map every day
 | ||||
| 		$last_generated_time = filemtime($this->sitemap_filepath); | ||||
| 
 | ||||
| 		// if file doesn't exist, return true
 | ||||
|             if ($last_generated_time == false) return true; | ||||
| 		if ($last_generated_time == false) { | ||||
| 			return true; | ||||
| 		} | ||||
| 
 | ||||
| 		// if it's been a day since last sitemap creation, return true
 | ||||
|             if ($last_generated_time + $sitemap_generation_interval < time()) | ||||
| 		if ($last_generated_time + $sitemap_generation_interval < time()) { | ||||
| 			return true; | ||||
|             else    return false; | ||||
| 		} else { | ||||
| 			return false; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	private function display_existing_sitemap() | ||||
|  | ||||
| @ -113,8 +113,9 @@ class Source_History extends Extension { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/* | ||||
| 	 * this function is called when a revert request is received | ||||
| 	/** | ||||
| 	 * This function is called when a revert request is received. | ||||
| 	 * @param int $revert_id | ||||
| 	 */ | ||||
| 	private function process_revert_request($revert_id) { | ||||
| 		global $page; | ||||
| @ -202,6 +203,10 @@ class Source_History extends Extension { | ||||
| 		$this->theme->display_revert_ip_results(); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param int $revert_id | ||||
| 	 * @return mixed|null | ||||
| 	 */ | ||||
| 	public function get_source_history_from_revert(/*int*/ $revert_id) { | ||||
| 		global $database; | ||||
| 		$row = $database->get_row(" | ||||
| @ -212,6 +217,10 @@ class Source_History extends Extension { | ||||
| 		return ($row ? $row : null); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param int $image_id | ||||
| 	 * @return array | ||||
| 	 */ | ||||
| 	public function get_source_history_from_id(/*int*/ $image_id) { | ||||
| 		global $database; | ||||
| 		$row = $database->get_all(" | ||||
| @ -224,6 +233,10 @@ class Source_History extends Extension { | ||||
| 		return ($row ? $row : array()); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param int $page_id | ||||
| 	 * @return array | ||||
| 	 */ | ||||
| 	public function get_global_source_history($page_id) { | ||||
| 		global $database; | ||||
| 		$row = $database->get_all(" | ||||
| @ -236,8 +249,12 @@ class Source_History extends Extension { | ||||
| 		return ($row ? $row : array()); | ||||
| 	} | ||||
| 
 | ||||
| 	/* | ||||
| 	/** | ||||
| 	 * This function attempts to revert all changes by a given IP within an (optional) timeframe. | ||||
| 	 * | ||||
| 	 * @param string $name | ||||
| 	 * @param string $ip | ||||
| 	 * @param string $date | ||||
| 	 */ | ||||
| 	public function process_revert_all_changes($name, $ip, $date) { | ||||
| 		global $database; | ||||
| @ -332,8 +349,10 @@ class Source_History extends Extension { | ||||
| 		log_info("source_history", 'Reverted '.count($result).' edits.'); | ||||
| 	} | ||||
| 
 | ||||
| 	/* | ||||
| 	 * this function is called just before an images source is changed | ||||
| 	/** | ||||
| 	 * This function is called just before an images source is changed. | ||||
| 	 * @param Image $image | ||||
| 	 * @param string $source | ||||
| 	 */ | ||||
| 	private function add_source_history($image, $source) { | ||||
| 		global $database, $config, $user; | ||||
|  | ||||
| @ -2,6 +2,11 @@ | ||||
| class Source_HistoryTheme extends Themelet { | ||||
| 	var $messages = array(); | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param Page $page | ||||
| 	 * @param int $image_id | ||||
| 	 * @param array $history | ||||
| 	 */ | ||||
| 	public function display_history_page(Page $page, /*int*/ $image_id, /*array*/ $history) { | ||||
| 		global $user; | ||||
| 		$start_string = " | ||||
| @ -45,6 +50,11 @@ class Source_HistoryTheme extends Themelet { | ||||
| 		$page->add_block(new Block("Source History", $history_html, "main", 10)); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param Page $page | ||||
| 	 * @param array $history | ||||
| 	 * @param int $page_number | ||||
| 	 */ | ||||
| 	public function display_global_page(Page $page, /*array*/ $history, /*int*/ $page_number) { | ||||
| 		$start_string = " | ||||
| 			<div style='text-align: left'> | ||||
| @ -93,8 +103,9 @@ class Source_HistoryTheme extends Themelet { | ||||
| 		$page->add_block(new Block("Navigation", $nav, "left")); | ||||
| 	} | ||||
| 
 | ||||
| 	/* | ||||
| 	/** | ||||
| 	 * Add a section to the admin page. | ||||
| 	 * @param string $validation_msg | ||||
| 	 */ | ||||
| 	public function display_admin_block(/*string*/ $validation_msg='') { | ||||
| 		global $page; | ||||
| @ -130,6 +141,10 @@ class Source_HistoryTheme extends Themelet { | ||||
| 		$page->add_block(new Block("Bulk Revert Results", $html)); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $title | ||||
| 	 * @param string $body | ||||
| 	 */ | ||||
| 	public function add_status(/*string*/ $title, /*string*/ $body) { | ||||
| 		$this->messages[] = '<p><b>'. $title .'</b><br>'. $body .'</p>'; | ||||
| 	} | ||||
|  | ||||
| @ -23,6 +23,7 @@ class StatsDInterface extends Extension { | ||||
| 		$time = microtime(true) - $_load_start; | ||||
| 		StatsDInterface::$stats["shimmie.$type.hits"] = "1|c"; | ||||
| 		StatsDInterface::$stats["shimmie.$type.time"] = "$time|ms"; | ||||
| 		StatsDInterface::$stats["shimmie.$type.time-db"] = "{$database->dbtime}|ms"; | ||||
| 		StatsDInterface::$stats["shimmie.$type.memory"] = memory_get_peak_usage(true)."|c"; | ||||
| 		StatsDInterface::$stats["shimmie.$type.files"] = count(get_included_files())."|c"; | ||||
| 		StatsDInterface::$stats["shimmie.$type.queries"] = $_execs."|c"; | ||||
| @ -76,6 +77,9 @@ class StatsDInterface extends Extension { | ||||
| 		StatsDInterface::$stats["shimmie.events.info-sets"] = "1|c"; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @return int | ||||
| 	 */ | ||||
| 	public function get_priority() {return 99;} | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
| @ -23,7 +23,14 @@ | ||||
|  *      </ul> | ||||
|  *    <li>Pools | ||||
|  *      <ul> | ||||
|  *        <li>pool=(PoolID, PoolTitle) -- add post to pool (if exists) | ||||
|  *        <li>pool=(PoolID, PoolTitle, lastcreated) -- add post to pool (if exists) | ||||
|  *        <li>pool=(PoolID, PoolTitle, lastcreated):(PoolOrder) -- add post to pool (if exists) with set pool order | ||||
|  *        <ul> | ||||
|  *          <li>pool=50 -- add post to pool with ID of 50 | ||||
|  *          <li>pool=10:25 -- add post to pool with ID of 10 and with order 25 | ||||
|  *          <li>pool=This_is_a_Pool -- add post to pool with a title of "This is a Pool" | ||||
|  *          <li>pool=lastcreated -- add post to the last pool the user created | ||||
|  *        </ul> | ||||
|  *      </ul> | ||||
|  *    <li>Post Relationships | ||||
|  *      <ul> | ||||
| @ -40,9 +47,15 @@ | ||||
|  * | ||||
|  */ | ||||
| class OwnerSetEvent extends Event { | ||||
| 	var $image; | ||||
| 	var $owner; | ||||
| 	/** @var \Image  */ | ||||
| 	public $image; | ||||
| 	/** @var \User  */ | ||||
| 	public $owner; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param Image $image | ||||
| 	 * @param User $owner | ||||
| 	 */ | ||||
| 	public function __construct(Image $image, User $owner) { | ||||
| 		$this->image = $image; | ||||
| 		$this->owner = $owner; | ||||
| @ -57,9 +70,15 @@ class OwnerSetEvent extends Event { | ||||
|  * | ||||
|  */ | ||||
| class SourceSetEvent extends Event { | ||||
| 	var $image; | ||||
| 	var $source; | ||||
| 	/** @var \Image */ | ||||
| 	public $image; | ||||
| 	/** @var string */ | ||||
| 	public $source; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param Image $image | ||||
| 	 * @param string $source | ||||
| 	 */ | ||||
| 	public function __construct(Image $image, $source) { | ||||
| 		$this->image = $image; | ||||
| 		$this->source = $source; | ||||
| @ -74,7 +93,8 @@ class SourceSetEvent extends Event { | ||||
|  * | ||||
|  */ | ||||
| class TagSetEvent extends Event { | ||||
| 	var $image; | ||||
| 	/** @var \Image */ | ||||
| 	public $image; | ||||
| 	var $tags; | ||||
| 
 | ||||
| 	public function __construct(Image $image, $tags) { | ||||
| @ -90,9 +110,15 @@ class TagSetEvent extends Event { | ||||
|  * | ||||
|  */ | ||||
| class LockSetEvent extends Event { | ||||
| 	var $image; | ||||
| 	var $locked; | ||||
| 	/** @var \Image */ | ||||
| 	public $image; | ||||
| 	/** @var bool */ | ||||
| 	public $locked; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param Image $image | ||||
| 	 * @param bool $locked | ||||
| 	 */ | ||||
| 	public function __construct(Image $image, $locked) { | ||||
| 		assert(is_bool($locked)); | ||||
| 		$this->image = $image; | ||||
| @ -107,13 +133,17 @@ class LockSetEvent extends Event { | ||||
| class TagTermParseEvent extends Event { | ||||
| 	var $term = null; | ||||
| 	var $id = null; | ||||
| 	var $metatag = false; | ||||
| 	/** @var bool */ | ||||
| 	public $metatag = false; | ||||
| 
 | ||||
| 	public function __construct($term, $id) { | ||||
| 		$this->term = $term; | ||||
| 		$this->id = $id; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @return bool | ||||
| 	 */ | ||||
| 	public function is_metatag() { | ||||
| 		return $this->metatag; | ||||
| 	} | ||||
| @ -150,10 +180,14 @@ class TagEdit extends Extension { | ||||
| 	} | ||||
| 
 | ||||
| 	public function onImageInfoSet(ImageInfoSetEvent $event) { | ||||
| 		global $user, $page; | ||||
| 		global $user; | ||||
| 		if($user->can("edit_image_owner")) { | ||||
| 			$owner = User::by_name($_POST['tag_edit__owner']); | ||||
| 			if ($owner instanceof User) { | ||||
| 				send_event(new OwnerSetEvent($event->image, $owner)); | ||||
| 			} else { | ||||
| 				throw new NullUserException("Error: No user with that name was found."); | ||||
| 			} | ||||
| 		} | ||||
| 		if($this->can_tag($event->image) && isset($_POST['tag_edit__tags'])) { | ||||
| 			send_event(new TagSetEvent($event->image, $_POST['tag_edit__tags'])); | ||||
| @ -205,13 +239,15 @@ class TagEdit extends Extension { | ||||
| 		$this->theme->display_mass_editor(); | ||||
| 	} | ||||
| 
 | ||||
| 	// When an alias is added, oldtag becomes inaccessable
 | ||||
| 	/** | ||||
| 	 * When an alias is added, oldtag becomes inaccessible. | ||||
| 	 * @param AddAliasEvent $event | ||||
| 	 */ | ||||
| 	public function onAddAlias(AddAliasEvent $event) { | ||||
| 		$this->mass_tag_edit($event->oldtag, $event->newtag); | ||||
| 	} | ||||
| 
 | ||||
| 	public function onImageInfoBoxBuilding(ImageInfoBoxBuildingEvent $event) { | ||||
| 		global $user; | ||||
| 		$event->add_part($this->theme->get_user_editor_html($event->image), 39); | ||||
| 		$event->add_part($this->theme->get_tag_editor_html($event->image), 40); | ||||
| 		$event->add_part($this->theme->get_source_editor_html($event->image), 41); | ||||
| @ -229,19 +265,30 @@ class TagEdit extends Extension { | ||||
| 		if(!empty($matches)) $event->metatag = true; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param Image $image | ||||
| 	 * @return bool | ||||
| 	 */ | ||||
| 	private function can_tag(Image $image) { | ||||
| 		global $config, $user; | ||||
| 		global $user; | ||||
| 		return ($user->can("edit_image_tag") || !$image->is_locked()); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param Image $image | ||||
| 	 * @return bool | ||||
| 	 */ | ||||
| 	private function can_source(Image $image) { | ||||
| 		global $config, $user; | ||||
| 		global $user; | ||||
| 		return ($user->can("edit_image_source") || !$image->is_locked()); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $search | ||||
| 	 * @param string $replace | ||||
| 	 */ | ||||
| 	private function mass_tag_edit($search, $replace) { | ||||
| 		global $database; | ||||
| 		global $config; | ||||
| 
 | ||||
| 		$search_set = Tag::explode(strtolower($search), false); | ||||
| 		$replace_set = Tag::explode(strtolower($replace), false); | ||||
| @ -296,10 +343,11 @@ class TagEdit extends Extension { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string|string[] $tags | ||||
| 	 * @param string $source | ||||
| 	 */ | ||||
| 	private function mass_source_edit($tags, $source) { | ||||
| 		global $database; | ||||
| 		global $config; | ||||
| 
 | ||||
| 		$tags = Tag::explode($tags); | ||||
| 
 | ||||
| 		$last_id = -1; | ||||
|  | ||||
| @ -99,6 +99,10 @@ class TagEditTheme extends Themelet { | ||||
| 		";
 | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $source | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	protected function format_source(/*string*/ $source) { | ||||
| 		if(!empty($source)) { | ||||
| 			if(!startsWith($source, "http://") && !startsWith($source, "https://")) { | ||||
|  | ||||
| @ -51,7 +51,11 @@ class TagEditCloud extends Extension { | ||||
| 		$event->panel->add_block($sb); | ||||
| 	} | ||||
| 
 | ||||
| 	private function build_tag_map($image) { | ||||
| 	/** | ||||
| 	 * @param Image $image | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	private function build_tag_map(Image $image) { | ||||
| 		global $database, $config; | ||||
| 
 | ||||
| 		$html = ""; | ||||
| @ -75,9 +79,12 @@ class TagEditCloud extends Extension { | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		$tag_data = null; | ||||
| 
 | ||||
| 		switch($sort_method){ | ||||
| 			case 'a': | ||||
| 			case 'p': | ||||
| 			default: | ||||
| 				$tag_data = $database->get_all("SELECT tag, FLOOR(LN(LN(count - :tag_min1 + 1)+1)*150)/200 AS scaled, count
 | ||||
| 					FROM tags WHERE count >= :tag_min2 ORDER BY ".($sort_method == 'a' ? "tag" : "count DESC")." LIMIT :limit",
 | ||||
| 					array("tag_min1" => $tags_min, "tag_min2" => $tags_min, "limit" => $max_count)); | ||||
| @ -115,15 +122,15 @@ class TagEditCloud extends Extension { | ||||
| 			$size = sprintf("%.2f", max($row['scaled'],0.5)); | ||||
| 			$js = htmlspecialchars('tageditcloud_toggle_tag(this,'.json_encode($full_tag).')',ENT_QUOTES); //Ugly, but it works
 | ||||
| 
 | ||||
| 			if(array_search($row['tag'],$image->tag_array) !== FALSE) { | ||||
| 			if(array_search($row['tag'],$image->get_tag_array()) !== FALSE) { | ||||
| 				if($used_first) { | ||||
| 					$precloud .= " <span onclick='$js' class='tag-selected' style='font-size: ${size}em$color' title='${row['count']}'>$h_tag</span> \n"; | ||||
| 					$precloud .= " <span onclick='{$js}' class='tag-selected' style='font-size: ${size}em$color' title='${row['count']}'>{$h_tag}</span> \n"; | ||||
| 					continue; | ||||
| 				} else { | ||||
| 					$entry = " <span onclick='$js' class='tag-selected' style='font-size: ${size}em$color' title='${row['count']}'>$h_tag</span> \n"; | ||||
| 					$entry = " <span onclick='{$js}' class='tag-selected' style='font-size: ${size}em$color' title='${row['count']}'>{$h_tag}</span> \n"; | ||||
| 				} | ||||
| 			} else { | ||||
| 				$entry = " <span onclick='$js' style='font-size: ${size}em$color' title='${row['count']}'>$h_tag</span> \n"; | ||||
| 				$entry = " <span onclick='{$js}' style='font-size: ${size}em$color' title='${row['count']}'>{$h_tag}</span> \n"; | ||||
| 			} | ||||
| 
 | ||||
| 			if($counter++ <= $def_count) { | ||||
| @ -134,24 +141,28 @@ class TagEditCloud extends Extension { | ||||
| 		} | ||||
| 
 | ||||
| 		if($precloud != '') { | ||||
| 			$html .= "<div id='tagcloud_set'>$precloud</div>"; | ||||
| 			$html .= "<div id='tagcloud_set'>{$precloud}</div>"; | ||||
| 		} | ||||
| 
 | ||||
| 		if($postcloud != '') { | ||||
| 			$postcloud = "<div id='tagcloud_extra' style='display: none;'>$postcloud</div>"; | ||||
| 			$postcloud = "<div id='tagcloud_extra' style='display: none;'>{$postcloud}</div>"; | ||||
| 		} | ||||
| 
 | ||||
| 		$html .= "<div id='tagcloud_unset'>$cloud$postcloud</div>"; | ||||
| 		$html .= "<div id='tagcloud_unset'>{$cloud}{$postcloud}</div>"; | ||||
| 
 | ||||
| 		if($sort_method != 'a' && $counter > $def_count) { | ||||
| 			$rem = $counter - $def_count; | ||||
| 			$html .= "</div><br>[<span onclick='tageditcloud_toggle_extra(this);' style='color: #0000EF; font-weight:bold;'>show $rem more tags</span>]"; | ||||
| 			$html .= "</div><br>[<span onclick='tageditcloud_toggle_extra(this);' style='color: #0000EF; font-weight:bold;'>show {$rem} more tags</span>]"; | ||||
| 		} | ||||
| 
 | ||||
| 		return "<div id='tageditcloud' class='tageditcloud'>$html</div>"; // FIXME: stupidasallhell
 | ||||
| 		return "<div id='tageditcloud' class='tageditcloud'>{$html}</div>"; // FIXME: stupidasallhell
 | ||||
| 	} | ||||
| 
 | ||||
| 	private function can_tag($image) { | ||||
| 	/** | ||||
| 	 * @param Image $image | ||||
| 	 * @return bool | ||||
| 	 */ | ||||
| 	private function can_tag(Image $image) { | ||||
| 		global $user; | ||||
| 		return ($user->can("edit_image_tag") && (!$image->is_locked() || $user->can("edit_image_lock"))); | ||||
| 	} | ||||
|  | ||||
| @ -24,7 +24,7 @@ class Tag_History extends Extension { | ||||
| 	} | ||||
| 
 | ||||
| 	public function onPageRequest(PageRequestEvent $event) { | ||||
| 		global $config, $page, $user; | ||||
| 		global $page, $user; | ||||
| 
 | ||||
| 		if($event->page_matches("tag_history/revert")) { | ||||
| 			// this is a request to revert to a previous version of the tags
 | ||||
| @ -113,8 +113,11 @@ class Tag_History extends Extension { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/* | ||||
| 	 * this function is called when a revert request is received | ||||
| 	/** | ||||
| 	 * This function is called when a revert request is received. | ||||
| 	 * | ||||
| 	 * @param int $revert_id | ||||
| 	 * @throws ImageDoesNotExist | ||||
| 	 */ | ||||
| 	private function process_revert_request($revert_id) { | ||||
| 		global $page; | ||||
| @ -200,6 +203,10 @@ class Tag_History extends Extension { | ||||
| 		$this->theme->display_revert_ip_results(); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param int $revert_id | ||||
| 	 * @return mixed|null | ||||
| 	 */ | ||||
| 	public function get_tag_history_from_revert(/*int*/ $revert_id) { | ||||
| 		global $database; | ||||
| 		$row = $database->get_row(" | ||||
| @ -210,6 +217,10 @@ class Tag_History extends Extension { | ||||
| 		return ($row ? $row : null); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param int $image_id | ||||
| 	 * @return array | ||||
| 	 */ | ||||
| 	public function get_tag_history_from_id(/*int*/ $image_id) { | ||||
| 		global $database; | ||||
| 		$row = $database->get_all(" | ||||
| @ -222,6 +233,10 @@ class Tag_History extends Extension { | ||||
| 		return ($row ? $row : array()); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param int $page_id | ||||
| 	 * @return array | ||||
| 	 */ | ||||
| 	public function get_global_tag_history($page_id) { | ||||
| 		global $database; | ||||
| 		$row = $database->get_all(" | ||||
| @ -328,16 +343,19 @@ class Tag_History extends Extension { | ||||
| 		log_info("tag_history", 'Reverted '.count($result).' edits.'); | ||||
| 	} | ||||
| 
 | ||||
| 	/* | ||||
| 	 * this function is called just before an images tag are changed | ||||
| 	/** | ||||
| 	 * This function is called just before an images tag are changed. | ||||
| 	 * | ||||
| 	 * @param Image $image | ||||
| 	 * @param string|string[] $tags | ||||
| 	 */ | ||||
| 	private function add_tag_history($image, $tags) { | ||||
| 	private function add_tag_history(Image $image, $tags) { | ||||
| 		global $database, $config, $user; | ||||
| 
 | ||||
| 		$new_tags = Tag::implode($tags); | ||||
| 		$old_tags = Tag::implode($image->get_tag_array()); | ||||
| 		 | ||||
| 		if($new_tags == $old_tags) return; | ||||
| 		if($new_tags == $old_tags) { return; } | ||||
| 		 | ||||
| 		if(empty($old_tags)) { | ||||
| 			/* no old tags, so we are probably adding the image for the first time */ | ||||
| @ -348,7 +366,7 @@ class Tag_History extends Extension { | ||||
| 		} | ||||
| 		 | ||||
| 		$allowed = $config->get_int("history_limit"); | ||||
| 		if($allowed == 0) return; | ||||
| 		if($allowed == 0) { return; } | ||||
| 		 | ||||
| 		// if the image has no history, make one with the old tags
 | ||||
| 		$entries = $database->get_one("SELECT COUNT(*) FROM tag_histories WHERE image_id = ?", array($image->id)); | ||||
| @ -368,7 +386,7 @@ class Tag_History extends Extension { | ||||
| 		$entries++; | ||||
| 		 | ||||
| 		// if needed remove oldest one
 | ||||
| 		if($allowed == -1) return; | ||||
| 		if($allowed == -1) { return; } | ||||
| 		if($entries > $allowed) { | ||||
| 			// TODO: Make these queries better
 | ||||
| 			/* | ||||
|  | ||||
| @ -7,6 +7,11 @@ | ||||
| class Tag_HistoryTheme extends Themelet { | ||||
| 	var $messages = array(); | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param Page $page | ||||
| 	 * @param int $image_id | ||||
| 	 * @param array $history | ||||
| 	 */ | ||||
| 	public function display_history_page(Page $page, /*int*/ $image_id, /*array*/ $history) { | ||||
| 		global $user; | ||||
| 		$start_string = " | ||||
| @ -57,6 +62,11 @@ class Tag_HistoryTheme extends Themelet { | ||||
| 		$page->add_block(new Block("Tag History", $history_html, "main", 10)); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param Page $page | ||||
| 	 * @param array $history | ||||
| 	 * @param int $page_number | ||||
| 	 */ | ||||
| 	public function display_global_page(Page $page, /*array*/ $history, /*int*/ $page_number) { | ||||
| 		$start_string = " | ||||
| 			<div style='text-align: left'> | ||||
| @ -105,8 +115,10 @@ class Tag_HistoryTheme extends Themelet { | ||||
| 		$page->add_block(new Block("Navigation", $nav, "left")); | ||||
| 	} | ||||
| 
 | ||||
| 	/* | ||||
| 	/** | ||||
| 	 * Add a section to the admin page. | ||||
| 	 * | ||||
| 	 * @param string $validation_msg | ||||
| 	 */ | ||||
| 	public function display_admin_block(/*string*/ $validation_msg='') { | ||||
| 		global $page; | ||||
| @ -142,6 +154,10 @@ class Tag_HistoryTheme extends Themelet { | ||||
| 		$page->add_block(new Block("Bulk Revert Results", $html)); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $title | ||||
| 	 * @param string $body | ||||
| 	 */ | ||||
| 	public function add_status(/*string*/ $title, /*string*/ $body) { | ||||
| 		$this->messages[] = '<p><b>'. $title .'</b><br>'. $body .'</p>'; | ||||
| 	} | ||||
|  | ||||
| @ -121,6 +121,10 @@ class TagList extends Extension { | ||||
| 	} | ||||
| // }}}
 | ||||
| // misc {{{
 | ||||
| 	/** | ||||
| 	 * @param string $tag | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	private function tag_link(/*string*/ $tag) { | ||||
| 		$u_tag = url_escape($tag); | ||||
| 		return make_link("post/list/$u_tag/1"); | ||||
| @ -129,7 +133,8 @@ class TagList extends Extension { | ||||
| 	/** | ||||
| 	 * Get the minimum number of times a tag needs to be used | ||||
| 	 * in order to be considered in the tag list. | ||||
| 	 * @retval int | ||||
| 	 * | ||||
| 	 * @return int | ||||
| 	 */ | ||||
| 	private function get_tags_min() { | ||||
| 		if(isset($_GET['mincount'])) { | ||||
| @ -141,6 +146,9 @@ class TagList extends Extension { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	private function get_starts_with() { | ||||
| 		global $config; | ||||
| 		if(isset($_GET['starts_with'])) { | ||||
| @ -156,6 +164,9 @@ class TagList extends Extension { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	private function build_az() { | ||||
| 		global $database; | ||||
| 
 | ||||
| @ -179,6 +190,10 @@ class TagList extends Extension { | ||||
| 	} | ||||
| // }}}
 | ||||
| // maps {{{
 | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	private function build_navigation() { | ||||
| 		$h_index = "<a href='".make_link()."'>Index</a>"; | ||||
| 		$h_map = "<a href='".make_link("tags/map")."'>Map</a>"; | ||||
| @ -189,6 +204,9 @@ class TagList extends Extension { | ||||
| 		return "$h_index<br> <br>$h_map<br>$h_alphabetic<br>$h_popularity<br>$h_cats<br> <br>$h_all"; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	private function build_tag_map() { | ||||
| 		global $config, $database; | ||||
| 
 | ||||
| @ -226,6 +244,9 @@ class TagList extends Extension { | ||||
| 		return $html; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	private function build_tag_alphabetic() { | ||||
| 		global $config, $database; | ||||
| 
 | ||||
| @ -279,6 +300,9 @@ class TagList extends Extension { | ||||
| 		return $html; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	private function build_tag_popularity() { | ||||
| 		global $database; | ||||
| 
 | ||||
| @ -318,6 +342,9 @@ class TagList extends Extension { | ||||
| 		return $html; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	private function build_tag_list() { | ||||
| 		global $database; | ||||
| 
 | ||||
| @ -344,9 +371,12 @@ class TagList extends Extension { | ||||
| 	} | ||||
| // }}}
 | ||||
| // blocks {{{
 | ||||
| 	/** | ||||
| 	 * @param Page $page | ||||
| 	 * @param Image $image | ||||
| 	 */ | ||||
| 	private function add_related_block(Page $page, Image $image) { | ||||
| 		global $database; | ||||
| 		global $config; | ||||
| 		global $database, $config; | ||||
| 
 | ||||
| 		$query = " | ||||
| 			SELECT t3.tag AS tag, t3.count AS calc_count, it3.tag_id | ||||
| @ -376,9 +406,12 @@ class TagList extends Extension { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param Page $page | ||||
| 	 * @param Image $image | ||||
| 	 */ | ||||
| 	private function add_split_tags_block(Page $page, Image $image) { | ||||
| 		global $database; | ||||
| 		global $config; | ||||
| 
 | ||||
| 		$query = " | ||||
| 			SELECT tags.tag, tags.count as calc_count | ||||
| @ -395,9 +428,12 @@ class TagList extends Extension { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param Page $page | ||||
| 	 * @param Image $image | ||||
| 	 */ | ||||
| 	private function add_tags_block(Page $page, Image $image) { | ||||
| 		global $database; | ||||
| 		global $config; | ||||
| 
 | ||||
| 		$query = " | ||||
| 			SELECT tags.tag, tags.count as calc_count | ||||
| @ -414,9 +450,11 @@ class TagList extends Extension { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param Page $page | ||||
| 	 */ | ||||
| 	private function add_popular_block(Page $page) { | ||||
| 		global $database; | ||||
| 		global $config; | ||||
| 		global $database, $config; | ||||
| 
 | ||||
| 		$tags = $database->cache->get("popular_tags"); | ||||
| 		if(empty($tags)) { | ||||
| @ -437,9 +475,12 @@ class TagList extends Extension { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param Page $page | ||||
| 	 * @param string[] $search | ||||
| 	 */ | ||||
| 	private function add_refine_block(Page $page, /*array(string)*/ $search) { | ||||
| 		global $database; | ||||
| 		global $config; | ||||
| 		global $database, $config; | ||||
| 
 | ||||
| 		$wild_tags = Tag::explode($search); | ||||
| 		$str_search = Tag::implode($search); | ||||
|  | ||||
| @ -1,13 +1,23 @@ | ||||
| <?php | ||||
| 
 | ||||
| class TagListTheme extends Themelet { | ||||
| 	var $heading = ""; | ||||
| 	var $list = ""; | ||||
| 	/** @var string  */ | ||||
| 	public $heading = ""; | ||||
| 	/** @var string|string[]  */ | ||||
| 	public $list = ""; | ||||
| 
 | ||||
| 	public $navigation; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $text | ||||
| 	 */ | ||||
| 	public function set_heading($text) { | ||||
| 		$this->heading = $text; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string|string[] $list | ||||
| 	 */ | ||||
| 	public function set_tag_list($list) { | ||||
| 		$this->list = $list; | ||||
| 	} | ||||
| @ -219,6 +229,11 @@ class TagListTheme extends Themelet { | ||||
| 		return array($category, $display_html); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $tag | ||||
| 	 * @param string[] $tags | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	protected function ars(/*string*/ $tag, /*array(string)*/ $tags) { | ||||
| 		assert(is_array($tags)); | ||||
| 
 | ||||
| @ -234,6 +249,11 @@ class TagListTheme extends Themelet { | ||||
| 		return $html; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param array $tags | ||||
| 	 * @param string $tag | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	protected function get_remove_link($tags, $tag) { | ||||
| 		if(!in_array($tag, $tags) && !in_array("-$tag", $tags)) { | ||||
| 			return ""; | ||||
| @ -245,6 +265,11 @@ class TagListTheme extends Themelet { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param array $tags | ||||
| 	 * @param string $tag | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	protected function get_add_link($tags, $tag) { | ||||
| 		if(in_array($tag, $tags)) { | ||||
| 			return ""; | ||||
| @ -256,6 +281,11 @@ class TagListTheme extends Themelet { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param array $tags | ||||
| 	 * @param string $tag | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	protected function get_subtract_link($tags, $tag) { | ||||
| 		if(in_array("-$tag", $tags)) { | ||||
| 			return ""; | ||||
| @ -267,6 +297,10 @@ class TagListTheme extends Themelet { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param string $tag | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	protected function tag_link($tag) { | ||||
| 		$u_tag = url_escape($tag); | ||||
| 		return make_link("post/list/$u_tag/1"); | ||||
|  | ||||
| @ -132,10 +132,13 @@ class Tips extends Extension { | ||||
| 		$this->theme->showAll($url, $tips); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param int $tipID | ||||
| 	 */ | ||||
| 	private function setStatus($tipID) { | ||||
| 		global $database; | ||||
| 
 | ||||
| 		$tip = $database->get_row("SELECT * FROM tips WHERE id = ? ", array($tipID)); | ||||
| 		$tip = $database->get_row("SELECT * FROM tips WHERE id = ? ", array(int_escape($tipID))); | ||||
| 
 | ||||
| 		if (bool_escape($tip['enable'])) { | ||||
| 			$enable = "N"; | ||||
| @ -143,12 +146,15 @@ class Tips extends Extension { | ||||
| 			$enable = "Y"; | ||||
| 		} | ||||
| 
 | ||||
| 		$database->execute("UPDATE tips SET enable = ? WHERE id = ?", array ($enable, $tipID)); | ||||
| 		$database->execute("UPDATE tips SET enable = ? WHERE id = ?", array ($enable, int_escape($tipID))); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param int $tipID | ||||
| 	 */ | ||||
| 	private function deleteTip($tipID) { | ||||
| 		global $database; | ||||
| 		$database->execute("DELETE FROM tips WHERE id = ?", array($tipID)); | ||||
| 		$database->execute("DELETE FROM tips WHERE id = ?", array(int_escape($tipID))); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -1,24 +0,0 @@ | ||||
| <?php | ||||
| /* | ||||
|  * Name: Tweet! | ||||
|  * Author: Shish <webmaster@shishnet.org> | ||||
|  * Link: http://code.shishnet.org/shimmie2/ | ||||
|  * License: GPLv2 | ||||
|  * Description: Show a twitter feed with the Sea of Clouds script | ||||
|  */ | ||||
| 
 | ||||
| class TwitterSoc extends Extension { | ||||
| 	public function onPostListBuilding(PostListBuildingEvent $event) { | ||||
| 		global $config, $page; | ||||
| 		if(strlen($config->get_string("twitter_soc_username")) > 0) { | ||||
| 			$this->theme->display_feed($page, $config->get_string("twitter_soc_username")); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	public function onSetupBuilding(SetupBuildingEvent $event) { | ||||
| 		$sb = new SetupBlock("Tweet!"); | ||||
| 		$sb->add_text_option("twitter_soc_username", "Username "); | ||||
| 		$event->panel->add_block($sb); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user