summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathan Kinkade <nkinkade@nkinka.de>2010-12-23 02:12:38 +0000
committerNathan Kinkade <nkinkade@nkinka.de>2010-12-23 02:12:38 +0000
commit5e17a5e7fcb678bd7081bdf8089afec5b25f3aff (patch)
tree9590eae390af1f72b72ddc6500a2566e3558e3bb
parentcf1965957c48b1c88a3913f8167688d03d191cec (diff)
parent032e6fde5f99c3150a4ae70e410ce314d8c3877a (diff)
Merge branch 'master' of git://github.com/gallery/gallery3
-rw-r--r--installer/installer.php27
-rw-r--r--modules/digibug/controllers/digibug.php2
-rw-r--r--modules/digibug/tests/Digibug_Controller_Test.php2
-rw-r--r--modules/gallery/config/user_agents.php138
-rw-r--r--modules/gallery/controllers/file_proxy.php26
-rw-r--r--modules/gallery/controllers/upgrader.php2
-rw-r--r--modules/gallery/helpers/MY_url.php42
-rw-r--r--modules/gallery/helpers/access.php14
-rw-r--r--modules/gallery/helpers/block_manager.php2
-rw-r--r--modules/gallery/helpers/gallery_event.php7
-rw-r--r--modules/gallery/helpers/gallery_installer.php4
-rw-r--r--modules/gallery/helpers/item.php71
-rw-r--r--modules/gallery/helpers/items_rest.php6
-rw-r--r--modules/gallery/helpers/random.php50
-rw-r--r--modules/gallery/helpers/tree_rest.php92
-rw-r--r--modules/gallery/libraries/Admin_View.php6
-rw-r--r--modules/gallery/libraries/Menu.php5
-rw-r--r--modules/gallery/libraries/Theme_View.php2
-rw-r--r--modules/gallery/models/item.php97
-rw-r--r--modules/gallery/tests/Albums_Controller_Test.php2
-rw-r--r--modules/gallery/tests/Cache_Test.php30
-rw-r--r--modules/gallery/tests/Item_Helper_Test.php108
-rw-r--r--modules/gallery/tests/Item_Model_Test.php37
-rw-r--r--modules/gallery/tests/Items_Rest_Helper_Test.php14
-rw-r--r--modules/gallery/tests/xss_data.txt8
-rw-r--r--modules/gallery/views/form_uploadify.html.php4
-rw-r--r--modules/gallery_unit_test/controllers/gallery_unit_test.php1
-rw-r--r--modules/gallery_unit_test/helpers/test.php12
-rw-r--r--modules/image_block/helpers/image_block_installer.php12
-rw-r--r--modules/image_block/module.info2
-rw-r--r--modules/rest/helpers/rest.php7
-rw-r--r--modules/rest/helpers/rest_event.php6
-rw-r--r--modules/unit_test/libraries/Unit_Test.php2
-rw-r--r--modules/user/controllers/password.php2
-rw-r--r--modules/user/models/group.php8
-rw-r--r--modules/user/models/user.php8
-rw-r--r--themes/admin_wind/css/screen.css2
37 files changed, 597 insertions, 263 deletions
diff --git a/installer/installer.php b/installer/installer.php
index 9a957b43..1771e3aa 100644
--- a/installer/installer.php
+++ b/installer/installer.php
@@ -138,7 +138,7 @@ class installer {
$char += ($char > 90) ? 13 : ($char > 57) ? 7 : 0;
$salt .= chr($char);
}
- $password = substr(md5(time() * rand()), 0, 6);
+ $password = substr(md5(time() . mt_rand()), 0, 6);
// Escape backslash in preparation for our UPDATE statement.
$hashed_password = str_replace("\\", "\\\\", $salt . md5($salt . $password));
$sql = self::prepend_prefix($config["prefix"],
@@ -152,7 +152,7 @@ class installer {
}
static function create_admin_session($config) {
- $session_id = md5(time() * rand());
+ $session_id = md5(time() . mt_rand());
$user_agent = $_SERVER["HTTP_USER_AGENT"];
$user_agent_len = strlen($user_agent);
$now = time();
@@ -233,7 +233,30 @@ class installer {
$errors[] = "Gallery requires the <a href=\"http://php.net/manual/en/book.ctype.php\">PHP Ctype</a> extension. Please install it.";
}
+ if (self::ini_get_bool("safe_mode")) {
+ $errors[] = "Gallery cannot function when PHP is in <a href=\"http://php.net/manual/en/features.safe-mode.php\">Safe Mode</a>. Please disable safe mode.";
+ }
+
return @$errors;
}
+ /**
+ * Convert any possible boolean ini value to true/false.
+ * On = on = 1 = true
+ * Off = off = 0 = false
+ */
+ static function ini_get_bool($varname) {
+ $value = ini_get($varname);
+
+ if (!strcasecmp("on", $value) || $value == 1 || $value === true) {
+ return true;
+ }
+
+ if (!strcasecmp("off", $value) || $value == 0 || $value === false) {
+ return false;
+ }
+
+ return false;
+ }
+
}
diff --git a/modules/digibug/controllers/digibug.php b/modules/digibug/controllers/digibug.php
index 88d1ace0..bc0c7c5e 100644
--- a/modules/digibug/controllers/digibug.php
+++ b/modules/digibug/controllers/digibug.php
@@ -28,7 +28,7 @@ class Digibug_Controller extends Controller {
$thumb_url = $item->thumb_url(true);
} else {
$proxy = ORM::factory("digibug_proxy");
- $proxy->uuid = md5(rand());
+ $proxy->uuid = random::hash();
$proxy->item_id = $item->id;
$proxy->save();
$full_url = url::abs_site("digibug/print_proxy/full/$proxy->uuid");
diff --git a/modules/digibug/tests/Digibug_Controller_Test.php b/modules/digibug/tests/Digibug_Controller_Test.php
index 19a3f9da..d331b0ae 100644
--- a/modules/digibug/tests/Digibug_Controller_Test.php
+++ b/modules/digibug/tests/Digibug_Controller_Test.php
@@ -36,7 +36,7 @@ class Digibug_Controller_Test extends Gallery_Unit_Test_Case {
access::deny(identity::registered_users(), "view_full", $album);
$proxy = ORM::factory("digibug_proxy");
- $proxy->uuid = md5(rand());
+ $proxy->uuid = random::hash();
$proxy->item_id = $photo->id;
return $proxy->save();
}
diff --git a/modules/gallery/config/user_agents.php b/modules/gallery/config/user_agents.php
index 24720046..4e82e7d4 100644
--- a/modules/gallery/config/user_agents.php
+++ b/modules/gallery/config/user_agents.php
@@ -1,122 +1,22 @@
-<?php defined('SYSPATH') OR die('No direct access allowed.');
+<?php defined("SYSPATH") or die("No direct script access.");
/**
- * This file contains four arrays of user agent data. It is used by the
- * User Agent library to help identify browser, platform, robot, and
- * mobile device data. The array keys are used to identify the device
- * and the array values are used to set the actual name of the item.
+ * Gallery - a web based photo album viewer and editor
+ * Copyright (C) 2000-2010 Bharat Mediratta
*
- * @package Kohana
- * @author Kohana Team
- * @copyright (c) 2007-2009 Kohana Team
- * @license http://kohanaphp.com/license
- */
-
-$config['platform'] = array
-(
- 'windows nt 6.0' => 'Windows Vista',
- 'windows nt 5.2' => 'Windows 2003',
- 'windows nt 5.0' => 'Windows 2000',
- 'windows nt 5.1' => 'Windows XP',
- 'windows nt 4.0' => 'Windows NT',
- 'winnt4.0' => 'Windows NT',
- 'winnt 4.0' => 'Windows NT',
- 'winnt' => 'Windows NT',
- 'windows 98' => 'Windows 98',
- 'win98' => 'Windows 98',
- 'windows 95' => 'Windows 95',
- 'win95' => 'Windows 95',
- 'windows' => 'Unknown Windows OS',
- 'os x' => 'Mac OS X',
- 'intel mac' => 'Intel Mac',
- 'ppc mac' => 'PowerPC Mac',
- 'powerpc' => 'PowerPC',
- 'ppc' => 'PowerPC',
- 'cygwin' => 'Cygwin',
- 'linux' => 'Linux',
- 'debian' => 'Debian',
- 'openvms' => 'OpenVMS',
- 'sunos' => 'Sun Solaris',
- 'amiga' => 'Amiga',
- 'beos' => 'BeOS',
- 'apachebench' => 'ApacheBench',
- 'freebsd' => 'FreeBSD',
- 'netbsd' => 'NetBSD',
- 'bsdi' => 'BSDi',
- 'openbsd' => 'OpenBSD',
- 'os/2' => 'OS/2',
- 'warp' => 'OS/2',
- 'aix' => 'AIX',
- 'irix' => 'Irix',
- 'osf' => 'DEC OSF',
- 'hp-ux' => 'HP-UX',
- 'hurd' => 'GNU/Hurd',
- 'unix' => 'Unknown Unix OS',
-);
-
-/**
- * The order of this array should NOT be changed. Many browsers return
- * multiple browser types so we want to identify the sub-type first.
- */
-$config['browser'] = array
-(
- 'Opera' => 'Opera',
- 'MSIE' => 'Internet Explorer',
- 'Internet Explorer' => 'Internet Explorer',
- 'Shiira' => 'Shiira',
- 'Firefox' => 'Firefox',
- 'Chimera' => 'Chimera',
- 'Phoenix' => 'Phoenix',
- 'Firebird' => 'Firebird',
- 'Camino' => 'Camino',
- 'Netscape' => 'Netscape',
- 'OmniWeb' => 'OmniWeb',
- 'Chrome' => 'Chrome',
- 'Safari' => 'Safari',
- 'Konqueror' => 'Konqueror',
- 'Epiphany' => 'Epiphany',
- 'Galeon' => 'Galeon',
- 'Mozilla' => 'Mozilla',
- 'icab' => 'iCab',
- 'lynx' => 'Lynx',
- 'links' => 'Links',
- 'hotjava' => 'HotJava',
- 'amaya' => 'Amaya',
- 'IBrowse' => 'IBrowse',
-);
-
-$config['mobile'] = array
-(
- 'mobileexplorer' => 'Mobile Explorer',
- 'openwave' => 'Open Wave',
- 'opera mini' => 'Opera Mini',
- 'operamini' => 'Opera Mini',
- 'elaine' => 'Palm',
- 'palmsource' => 'Palm',
- 'digital paths' => 'Palm',
- 'avantgo' => 'Avantgo',
- 'xiino' => 'Xiino',
- 'palmscape' => 'Palmscape',
- 'nokia' => 'Nokia',
- 'ericsson' => 'Ericsson',
- 'blackBerry' => 'BlackBerry',
- 'motorola' => 'Motorola',
- 'iphone' => 'iPhone',
- 'android' => 'Android',
-);
-
-/**
- * There are hundreds of bots but these are the most common.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
-$config['robot'] = array
-(
- 'googlebot' => 'Googlebot',
- 'msnbot' => 'MSNBot',
- 'slurp' => 'Inktomi Slurp',
- 'yahoo' => 'Yahoo',
- 'askjeeves' => 'AskJeeves',
- 'fastcrawler' => 'FastCrawler',
- 'infoseek' => 'InfoSeek Robot 1.0',
- 'lycos' => 'Lycos',
- 'mj12bot' => 'MJ12bot',
- 'speedy spider' => 'Speedy Spider',
-); \ No newline at end of file
+include(SYSPATH . "config/user_agents.php");
+$config["robot"]["mj12bot"] = "MJ12bot";
+$config["robot"]["speedy spider"] = "Speedy Spider";
diff --git a/modules/gallery/controllers/file_proxy.php b/modules/gallery/controllers/file_proxy.php
index b17310c4..22854fbd 100644
--- a/modules/gallery/controllers/file_proxy.php
+++ b/modules/gallery/controllers/file_proxy.php
@@ -56,28 +56,16 @@ class File_Proxy_Controller extends Controller {
// If the last element is .album.jpg, pop that off since it's not a real item
$path = preg_replace("|/.album.jpg$|", "", $path);
- $encoded_path = array();
- foreach (explode("/", $path) as $path_part) {
- $encoded_path[] = rawurlencode($path_part);
- }
- $encoded_path = implode("/", $encoded_path);
- // We now have the relative path to the item. Search for it in the path cache
- // The patch cache is urlencoded so re-encode the path. (it was decoded earlier to
- // insure that the paths are normalized.
- $item = ORM::factory("item")
- ->where("relative_path_cache", "=", $encoded_path)->find();
- if (!$item->loaded()) {
- // We didn't turn it up. It's possible that the relative_path_cache is out of date here.
- // There was fallback code, but bharat deleted it in 8f1bca74. If it turns out to be
- // necessary, it's easily resurrected.
- // If we're looking for a .jpg then it's it's possible that we're requesting the thumbnail
- // for a movie. In that case, the .flv, .mp4 or .m4v file would have been converted to a
- // .jpg. So try some alternate types:
+ $item = item::find_by_path($path);
+ if (!$item->loaded()) {
+ // We didn't turn it up. If we're looking for a .jpg then it's it's possible that we're
+ // requesting the thumbnail for a movie. In that case, the .flv, .mp4 or .m4v file would
+ // have been converted to a .jpg. So try some alternate types:
if (preg_match('/.jpg$/', $path)) {
foreach (array("flv", "mp4", "m4v") as $ext) {
- $movie_path = preg_replace('/.jpg$/', ".$ext", $encoded_path);
- $item = ORM::factory("item")->where("relative_path_cache", "=", $movie_path)->find();
+ $movie_path = preg_replace('/.jpg$/', ".$ext", $path);
+ $item = item::find_by_path($movie_path);
if ($item->loaded()) {
break;
}
diff --git a/modules/gallery/controllers/upgrader.php b/modules/gallery/controllers/upgrader.php
index b2646874..66c71648 100644
--- a/modules/gallery/controllers/upgrader.php
+++ b/modules/gallery/controllers/upgrader.php
@@ -23,7 +23,7 @@ class Upgrader_Controller extends Controller {
// Make sure we have an upgrade token
if (!($upgrade_token = $session->get("upgrade_token", null))) {
- $session->set("upgrade_token", $upgrade_token = md5(rand()));
+ $session->set("upgrade_token", $upgrade_token = random::hash());
}
// If the upgrade token exists, then bless this session
diff --git a/modules/gallery/helpers/MY_url.php b/modules/gallery/helpers/MY_url.php
index 877c5ada..8ac26602 100644
--- a/modules/gallery/helpers/MY_url.php
+++ b/modules/gallery/helpers/MY_url.php
@@ -31,7 +31,7 @@ class url extends url_Core {
return;
}
- $item = self::get_item_from_uri(Router::$current_uri);
+ $item = item::find_by_relative_url(html_entity_decode(Router::$current_uri, ENT_QUOTES));
if ($item && $item->loaded()) {
Router::$controller = "{$item->type}s";
Router::$controller_path = MODPATH . "gallery/controllers/{$item->type}s.php";
@@ -41,32 +41,6 @@ class url extends url_Core {
}
/**
- * Locate an item using the URI. We assume that the uri is in the form /a/b/c where each
- * component matches up with an item slug.
- * @param string $uri the uri fragment
- * @return Item_Model
- */
- static function get_item_from_uri($uri) {
- $current_uri = html_entity_decode($uri, ENT_QUOTES);
- // In most cases, we'll have an exact match in the relative_url_cache item field.
- // but failing that, walk down the tree until we find it. The fallback code will fix caches
- // as it goes, so it'll never be run frequently.
- $item = ORM::factory("item")->where("relative_url_cache", "=", $current_uri)->find();
- if (!$item->loaded()) {
- $count = count(Router::$segments);
- foreach (ORM::factory("item")
- ->where("slug", "=", html_entity_decode(Router::$segments[$count - 1], ENT_QUOTES))
- ->where("level", "=", $count + 1)
- ->find_all() as $match) {
- if ($match->relative_url() == $current_uri) {
- $item = $match;
- }
- }
- }
- return $item;
- }
-
- /**
* Just like url::file() except that it returns an absolute URI
*/
static function abs_file($path) {
@@ -101,4 +75,18 @@ class url extends url_Core {
static function current($qs=false, $suffix=false) {
return htmlspecialchars(parent::current($qs, $suffix));
}
+
+ /**
+ * Merge extra an query string onto a given url safely.
+ * @param string the original url
+ * @param array the query string data in key=value form
+ */
+ static function merge_querystring($url, $query_params) {
+ $qs = implode("&", $query_params);
+ if (strpos($url, "?") === false) {
+ return $url . "?$qs";
+ } else {
+ return $url . "&$qs";
+ }
+ }
}
diff --git a/modules/gallery/helpers/access.php b/modules/gallery/helpers/access.php
index 0b0dcbc1..4148049a 100644
--- a/modules/gallery/helpers/access.php
+++ b/modules/gallery/helpers/access.php
@@ -99,8 +99,12 @@ class access_Core {
return true;
}
+ // Use the nearest parent album (including the current item) so that we take advantage
+ // of the cache when checking many items in a single album.
+ $id = ($item->type == "album") ? $item->id : $item->parent_id;
$resource = $perm_name == "view" ?
- $item : model_cache::get("access_cache", $item->id, "item_id");
+ $item : model_cache::get("access_cache", $id, "item_id");
+
foreach ($user->groups() as $group) {
if ($resource->__get("{$perm_name}_{$group->id}") === access::ALLOW) {
return true;
@@ -136,8 +140,12 @@ class access_Core {
* @return boolean
*/
static function group_can($group, $perm_name, $item) {
+ // Use the nearest parent album (including the current item) so that we take advantage
+ // of the cache when checking many items in a single album.
+ $id = ($item->type == "album") ? $item->id : $item->parent_id;
$resource = $perm_name == "view" ?
- $item : model_cache::get("access_cache", $item->id, "item_id");
+ $item : model_cache::get("access_cache", $id, "item_id");
+
return $resource->__get("{$perm_name}_{$group->id}") === access::ALLOW;
}
@@ -426,7 +434,7 @@ class access_Core {
$session = Session::instance();
$csrf = $session->get("csrf");
if (empty($csrf)) {
- $csrf = md5(rand());
+ $csrf = random::hash();
$session->set("csrf", $csrf);
}
return $csrf;
diff --git a/modules/gallery/helpers/block_manager.php b/modules/gallery/helpers/block_manager.php
index 2237b702..4bd649c2 100644
--- a/modules/gallery/helpers/block_manager.php
+++ b/modules/gallery/helpers/block_manager.php
@@ -28,7 +28,7 @@ class block_manager_Core {
static function add($location, $module_name, $block_id) {
$blocks = block_manager::get_active($location);
- $blocks[rand()] = array($module_name, $block_id);
+ $blocks[random::int()] = array($module_name, $block_id);
block_manager::set_active($location, $blocks);
}
diff --git a/modules/gallery/helpers/gallery_event.php b/modules/gallery/helpers/gallery_event.php
index b59bb9b9..5d3ee6ee 100644
--- a/modules/gallery/helpers/gallery_event.php
+++ b/modules/gallery/helpers/gallery_event.php
@@ -178,6 +178,10 @@ class gallery_event_Core {
}
Session::instance()->set("active_auth_timestamp", time());
auth::clear_failed_attempts($user);
+
+ if ($user->admin && ini_get("session.use_trans_sid")) {
+ message::info(t("PHP is configured with <a href=\"url\">session.use_trans_sid</a> enabled which will cause random logouts. Please disable this setting.", array("url" => "http://www.php.net/manual/en/session.configuration.php#ini.session.use-trans-sid")));
+ }
}
static function user_auth_failed($name) {
@@ -371,6 +375,9 @@ class gallery_event_Core {
->id("admin_menu")
->label(t("Admin")));
module::event("admin_menu", $admin_menu, $theme);
+
+ $settings_menu = $admin_menu->get("settings_menu");
+ sort($settings_menu->elements);
}
}
}
diff --git a/modules/gallery/helpers/gallery_installer.php b/modules/gallery/helpers/gallery_installer.php
index 3d82bc69..a6b8e6a2 100644
--- a/modules/gallery/helpers/gallery_installer.php
+++ b/modules/gallery/helpers/gallery_installer.php
@@ -459,7 +459,7 @@ class gallery_installer {
$blocks = block_manager::get_active($location);
$new_blocks = array();
foreach ($blocks as $block) {
- $new_blocks[rand()] = $block;
+ $new_blocks[random::int()] = $block;
}
block_manager::set_active($location, $new_blocks);
}
@@ -507,7 +507,7 @@ class gallery_installer {
->execute() as $row) {
$new_slug = item::convert_filename_to_slug($row->slug);
if (empty($new_slug)) {
- $new_slug = rand();
+ $new_slug = random::int();
}
db::build()
->update("items")
diff --git a/modules/gallery/helpers/item.php b/modules/gallery/helpers/item.php
index 052b1c8e..29dd8603 100644
--- a/modules/gallery/helpers/item.php
+++ b/modules/gallery/helpers/item.php
@@ -210,6 +210,75 @@ class item_Core {
}
/**
+ * Find an item by its path. If there's no match, return an empty Item_Model.
+ * NOTE: the caller is responsible for performing security checks on the resulting item.
+ * @param string $path
+ * @return object Item_Model
+ */
+ static function find_by_path($path) {
+ $path = trim($path, "/");
+
+ // The root path name is NULL not "", hence this workaround.
+ if ($path == "") {
+ return item::root();
+ }
+
+ // Check to see if there's an item in the database with a matching relative_path_cache value.
+ // Since that field is urlencoded, we must urlencoded the components of the path.
+ foreach (explode("/", $path) as $part) {
+ $encoded_array[] = rawurlencode($part);
+ }
+ $encoded_path = join("/", $encoded_array);
+ $item = ORM::factory("item")
+ ->where("relative_path_cache", "=", $encoded_path)
+ ->find();
+ if ($item->loaded()) {
+ return $item;
+ }
+
+ // Since the relative_path_cache field is a cache, it can be unavailable. If we don't find
+ // anything, fall back to checking the path the hard way.
+ $paths = explode("/", $path);
+ foreach (ORM::factory("item")
+ ->where("name", "=", end($paths))
+ ->where("level", "=", count($paths) + 1)
+ ->find_all() as $item) {
+ if (urldecode($item->relative_path()) == $path) {
+ return $item;
+ }
+ }
+
+ return new Item_Model();
+ }
+
+
+ /**
+ * Locate an item using the URL. We assume that the url is in the form /a/b/c where each
+ * component matches up with an item slug. If there's no match, return an empty Item_Model
+ * NOTE: the caller is responsible for performing security checks on the resulting item.
+ * @param string $url the relative url fragment
+ * @return Item_Model
+ */
+ static function find_by_relative_url($relative_url) {
+ // In most cases, we'll have an exact match in the relative_url_cache item field.
+ // but failing that, walk down the tree until we find it. The fallback code will fix caches
+ // as it goes, so it'll never be run frequently.
+ $item = ORM::factory("item")->where("relative_url_cache", "=", $relative_url)->find();
+ if (!$item->loaded()) {
+ $segments = explode("/", $relative_url);
+ foreach (ORM::factory("item")
+ ->where("slug", "=", end($segments))
+ ->where("level", "=", count($segments) + 1)
+ ->find_all() as $match) {
+ if ($match->relative_url() == $relative_url) {
+ $item = $match;
+ }
+ }
+ }
+ return $item;
+ }
+
+ /**
* Return the root Item_Model
* @return Item_Model
*/
@@ -232,7 +301,7 @@ class item_Core {
// distributed so this is going to be more efficient with larger data sets.
return ORM::factory("item")
->viewable()
- ->where("rand_key", "<", ((float)mt_rand()) / (float)mt_getrandmax())
+ ->where("rand_key", "<", random::percent())
->order_by("rand_key", "DESC");
}
} \ No newline at end of file
diff --git a/modules/gallery/helpers/items_rest.php b/modules/gallery/helpers/items_rest.php
index 08aa3279..3c09faa8 100644
--- a/modules/gallery/helpers/items_rest.php
+++ b/modules/gallery/helpers/items_rest.php
@@ -84,9 +84,9 @@ class items_rest_Core {
if ($item->type == "album") {
$members = array();
foreach ($item->viewable()->children() as $child) {
- if (empty($types) || in_array($child->type, $types)) {
- $members[] = rest::url("item", $child);
- }
+ if (empty($types) || in_array($child->type, $types)) {
+ $members[] = rest::url("item", $child);
+ }
}
$item_rest["members"] = $members;
}
diff --git a/modules/gallery/helpers/random.php b/modules/gallery/helpers/random.php
new file mode 100644
index 00000000..a26762bd
--- /dev/null
+++ b/modules/gallery/helpers/random.php
@@ -0,0 +1,50 @@
+<?php defined("SYSPATH") or die("No direct script access.");
+/**
+ * Gallery - a web based photo album viewer and editor
+ * Copyright (C) 2000-2010 Bharat Mediratta
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+class random_Core {
+ /**
+ * Return a random 32 bit hash value.
+ * @param string extra entropy data
+ */
+ static function hash($entropy="") {
+ return md5($entropy . uniqid(mt_rand(), true));
+ }
+
+ /**
+ * Return a random hexadecimal string of the given length.
+ * @param int the desired length of the string
+ */
+ static function string($length) {
+ return substr(random::hash(), 0, $length);
+ }
+
+ /**
+ * Return a random floating point number between 0 and 1
+ */
+ static function percent() {
+ return ((float)mt_rand()) / (float)mt_getrandmax();
+ }
+
+ /**
+ * Return a random number between 0 and mt_getrandmax()
+ */
+ static function int() {
+ return mt_rand();
+ }
+} \ No newline at end of file
diff --git a/modules/gallery/helpers/tree_rest.php b/modules/gallery/helpers/tree_rest.php
new file mode 100644
index 00000000..21928cbe
--- /dev/null
+++ b/modules/gallery/helpers/tree_rest.php
@@ -0,0 +1,92 @@
+<?php defined("SYSPATH") or die("No direct script access.");
+/**
+ * Gallery - a web based photo album viewer and editor
+ * Copyright (C) 2000-2010 Bharat Mediratta
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+class tree_rest_Core {
+ /**
+ * The tree is rooted in a single item and can have modifiers which adjust what data is shown
+ * for items inside the given tree, up to the depth that you want. The entity for this resource
+ * is a series of items.
+ *
+ * depth=<number>
+ * Only traverse this far down into the tree. If there are more albums
+ * below this depth, provide RESTful urls to other tree resources in
+ * the members section. Default is infinite.
+ *
+ * type=<album|photo|movie>
+ * Restrict the items displayed to the given type. Default is all types.
+ *
+ * fields=<comma separated list of field names>
+ * In the entity section only return these fields for each item.
+ * Default is all fields.
+ */
+ static function get($request) {
+ $item = rest::resolve($request->url);
+ access::required("view", $item);
+
+ $query_params = array();
+ $p = $request->params;
+ $where = array();
+ if (isset($p->type)) {
+ $where[] = array("type", "=", $p->type);
+ $query_params[] = "type={$p->type}";
+ }
+
+ if (isset($p->depth)) {
+ $lowest_depth = $item->level + $p->depth;
+ $where[] = array("level", "<=", $lowest_depth);
+ $query_params[] = "depth={$p->depth}";
+ }
+
+ $fields = array();
+ if (isset($p->fields)) {
+ $fields = explode(",", $p->fields);
+ $query_params[] = "fields={$p->fields}";
+ }
+
+ $entity = array(array("url" => rest::url("item", $item),
+ "entity" => $item->as_restful_array($fields)));
+ $members = array();
+ foreach ($item->viewable()->descendants(null, null, $where) as $child) {
+ $entity[] = array("url" => rest::url("item", $child),
+ "entity" => $child->as_restful_array($fields));
+ if (isset($lowest_depth) && $child->level == $lowest_depth) {
+ $members[] = url::merge_querystring(rest::url("tree", $child), $query_params);
+ }
+ }
+
+ $result = array(
+ "url" => $request->url,
+ "entity" => $entity,
+ "members" => $members,
+ "relationships" => rest::relationships("tree", $item));
+ return $result;
+ }
+
+ static function resolve($id) {
+ $item = ORM::factory("item", $id);
+ if (!access::can("view", $item)) {
+ throw new Kohana_404_Exception();
+ }
+ return $item;
+ }
+
+ static function url($item) {
+ return url::abs_site("rest/tree/{$item->id}");
+ }
+}
diff --git a/modules/gallery/libraries/Admin_View.php b/modules/gallery/libraries/Admin_View.php
index 88d86a7d..11f8ad14 100644
--- a/modules/gallery/libraries/Admin_View.php
+++ b/modules/gallery/libraries/Admin_View.php
@@ -44,6 +44,10 @@ class Admin_View_Core extends Gallery_View {
public function admin_menu() {
$menu = Menu::factory("root");
module::event("admin_menu", $menu, $this);
+
+ $settings_menu = $menu->get("settings_menu");
+ sort($settings_menu->elements);
+
return $menu->render();
}
@@ -93,8 +97,8 @@ class Admin_View_Core extends Gallery_View {
}
if ($function == "admin_head") {
- array_unshift($blocks, $this->combine_files($this->css, "css"));
array_unshift($blocks, $this->combine_files($this->scripts, "javascript"));
+ array_unshift($blocks, $this->combine_files($this->css, "css"));
}
if (Session::instance()->get("debug")) {
diff --git a/modules/gallery/libraries/Menu.php b/modules/gallery/libraries/Menu.php
index 3ad6ebef..58852a72 100644
--- a/modules/gallery/libraries/Menu.php
+++ b/modules/gallery/libraries/Menu.php
@@ -223,12 +223,13 @@ class Menu_Core extends Menu_Element {
/**
* Retrieve a Menu_Element by id
*/
- public function get($id) {
+ public function &get($id) {
if (array_key_exists($id, $this->elements)) {
return $this->elements[$id];
}
- return null;
+ $null = null;
+ return $null;
}
public function is_empty() {
diff --git a/modules/gallery/libraries/Theme_View.php b/modules/gallery/libraries/Theme_View.php
index 7a6bc1da..d22bb03a 100644
--- a/modules/gallery/libraries/Theme_View.php
+++ b/modules/gallery/libraries/Theme_View.php
@@ -284,8 +284,8 @@ class Theme_View_Core extends Gallery_View {
if ($function == "head") {
// Merge the theme CSS/JS at the end
$this->css = array_merge($this->css, $save_css);
- array_unshift($blocks, $this->combine_files($this->css, "css"));
array_unshift($blocks, $this->combine_files($this->scripts, "javascript"));
+ array_unshift($blocks, $this->combine_files($this->css, "css"));
}
if (Session::instance()->get("debug")) {
diff --git a/modules/gallery/models/item.php b/modules/gallery/models/item.php
index 9016a04a..fc5c3ff9 100644
--- a/modules/gallery/models/item.php
+++ b/modules/gallery/models/item.php
@@ -28,7 +28,7 @@ class Item_Model_Core extends ORM_MPTT {
if (!$this->loaded()) {
// Set reasonable defaults
$this->created = time();
- $this->rand_key = ((float)mt_rand()) / (float)mt_getrandmax();
+ $this->rand_key = random::percent();
$this->thumb_dirty = 1;
$this->resize_dirty = 1;
$this->sort_column = "created";
@@ -390,7 +390,7 @@ class Item_Model_Core extends ORM_MPTT {
if (file_exists($this->resize_path()) ||
file_exists($this->thumb_path())) {
$pi = pathinfo($this->name);
- $this->name = $pi["filename"] . "-" . rand() . "." . $pi["extension"];
+ $this->name = $pi["filename"] . "-" . random::int() . "." . $pi["extension"];
parent::save();
}
@@ -512,7 +512,7 @@ class Item_Model_Core extends ORM_MPTT {
->or_where("slug", "=", $this->slug)
->close()
->find()->id) {
- $rand = rand();
+ $rand = random::int();
if ($base_ext) {
$this->name = "$base_name-$rand.$base_ext";
} else {
@@ -848,10 +848,17 @@ class Item_Model_Core extends ORM_MPTT {
}
} else {
// New items must have an extension
- if (!pathinfo($this->name, PATHINFO_EXTENSION)) {
+ $ext = pathinfo($this->name, PATHINFO_EXTENSION);
+ if (!$ext) {
$v->add_error("name", "illegal_data_file_extension");
return;
}
+
+ if ($this->is_movie() && !preg_match("/^(flv|mp4|m4v)$/i", $ext)) {
+ $v->add_error("name", "illegal_data_file_extension");
+ } else if ($this->is_photo() && !preg_match("/^(gif|jpg|jpeg|png)$/i", $ext)) {
+ $v->add_error("name", "illegal_data_file_extension");
+ }
}
}
@@ -980,48 +987,88 @@ class Item_Model_Core extends ORM_MPTT {
/**
* Same as ORM::as_array() but convert id fields into their RESTful form.
+ *
+ * @param array if specified, only return the named fields
*/
- public function as_restful_array() {
+ public function as_restful_array($fields=array()) {
+ if ($fields) {
+ $data = array();
+ foreach ($fields as $field) {
+ if (isset($this->object[$field])) {
+ $data[$field] = $this->__get($field);
+ }
+ }
+ $fields = array_flip($fields);
+ } else {
+ $data = $this->as_array();
+ }
+
// Convert item ids to rest URLs for consistency
- $data = $this->as_array();
- if ($tmp = $this->parent()) {
- $data["parent"] = rest::url("item", $tmp);
+ if (empty($fields) || isset($fields["parent"])) {
+ if ($tmp = $this->parent()) {
+ $data["parent"] = rest::url("item", $tmp);
+ }
+ unset($data["parent_id"]);
}
- unset($data["parent_id"]);
- if ($tmp = $this->album_cover()) {
- $data["album_cover"] = rest::url("item", $tmp);
+
+ if (empty($fields) || isset($fields["album_cover"])) {
+ if ($tmp = $this->album_cover()) {
+ $data["album_cover"] = rest::url("item", $tmp);
+ }
+ unset($data["album_cover_item_id"]);
}
- unset($data["album_cover_item_id"]);
- $data["web_url"] = $this->abs_url();
+ if (empty($fields) || isset($fields["web_url"])) {
+ $data["web_url"] = $this->abs_url();
+ }
if (!$this->is_album()) {
if (access::can("view_full", $this)) {
- $data["file_url"] = rest::url("data", $this, "full");
- $data["file_size"] = filesize($this->file_path());
- }
- if (access::user_can(identity::guest(), "view_full", $this)) {
- $data["file_url_public"] = $this->file_url(true);
+ if (empty($fields) || isset($fields["file_url"])) {
+ $data["file_url"] = rest::url("data", $this, "full");
+ }
+ if (empty($fields) || isset($fields["file_size"])) {
+ $data["file_size"] = filesize($this->file_path());
+ }
+ if (access::user_can(identity::guest(), "view_full", $this)) {
+ if (empty($fields) || isset($fields["file_url_public"])) {
+ $data["file_url_public"] = $this->file_url(true);
+ }
+ }
}
}
if ($this->is_photo()) {
- $data["resize_url"] = rest::url("data", $this, "resize");
- $data["resize_size"] = filesize($this->resize_path());
+ if (empty($fields) || isset($fields["resize_url"])) {
+ $data["resize_url"] = rest::url("data", $this, "resize");
+ }
+ if (empty($fields) || isset($fields["resize_size"])) {
+ $data["resize_size"] = filesize($this->resize_path());
+ }
if (access::user_can(identity::guest(), "view", $this)) {
- $data["resize_url_public"] = $this->resize_url(true);
+ if (empty($fields) || isset($fields["resize_url_public"])) {
+ $data["resize_url_public"] = $this->resize_url(true);
+ }
}
}
if ($this->has_thumb()) {
- $data["thumb_url"] = rest::url("data", $this, "thumb");
- $data["thumb_size"] = filesize($this->thumb_path());
+ if (empty($fields) || isset($fields["thumb_url"])) {
+ $data["thumb_url"] = rest::url("data", $this, "thumb");
+ }
+ if (empty($fields) || isset($fields["thumb_size"])) {
+ $data["thumb_size"] = filesize($this->thumb_path());
+ }
if (access::user_can(identity::guest(), "view", $this)) {
- $data["thumb_url_public"] = $this->thumb_url(true);
+ if (empty($fields) || isset($fields["thumb_url_public"])) {
+ $data["thumb_url_public"] = $this->thumb_url(true);
+ }
}
}
- $data["can_edit"] = access::can("edit", $this);
+ if (empty($fields) || isset($fields["can_edit"])) {
+ $data["can_edit"] = access::can("edit", $this);
+ }
// Elide some internal-only data that is going to cause confusion in the client.
foreach (array("relative_path_cache", "relative_url_cache", "left_ptr", "right_ptr",
diff --git a/modules/gallery/tests/Albums_Controller_Test.php b/modules/gallery/tests/Albums_Controller_Test.php
index 6c64394d..35a3bdbb 100644
--- a/modules/gallery/tests/Albums_Controller_Test.php
+++ b/modules/gallery/tests/Albums_Controller_Test.php
@@ -31,7 +31,7 @@ class Albums_Controller_Test extends Gallery_Unit_Test_Case {
$album = test::random_album();
// Randomize to avoid conflicts.
- $new_name = "new_name_" . rand();
+ $new_name = "new_name_" . random::string(6);
$_POST["name"] = $new_name;
$_POST["title"] = "new title";
diff --git a/modules/gallery/tests/Cache_Test.php b/modules/gallery/tests/Cache_Test.php
index e8d8b6f4..b95ef0a2 100644
--- a/modules/gallery/tests/Cache_Test.php
+++ b/modules/gallery/tests/Cache_Test.php
@@ -27,7 +27,7 @@ class Cache_Test extends Gallery_Unit_Test_Case {
public function cache_exists_test() {
$this->assert_false($this->_driver->exists("test_key"), "test_key should not be defined");
- $id = md5(rand());
+ $id = random::hash();
db::build()
->insert("caches")
->columns("key", "tags", "expiration", "cache")
@@ -38,7 +38,7 @@ class Cache_Test extends Gallery_Unit_Test_Case {
}
public function cache_get_test() {
- $id = md5(rand());
+ $id = random::hash();
db::build()
->insert("caches")
@@ -54,7 +54,7 @@ class Cache_Test extends Gallery_Unit_Test_Case {
}
public function cache_set_test() {
- $id = md5(rand());
+ $id = random::hash();
$original_data = array("field1" => "value1", "field2" => "value2");
$this->_driver->set(array($id => $original_data), array("tag1", "tag2"), 84600);
@@ -63,15 +63,15 @@ class Cache_Test extends Gallery_Unit_Test_Case {
}
public function cache_get_tag_test() {
- $id1 = md5(rand());
+ $id1 = random::hash();
$value1 = array("field1" => "value1", "field2" => "value2");
$this->_driver->set(array($id1 => $value1), array("tag1", "tag2"), 84600);
- $id2 = md5(rand());
+ $id2 = random::hash();
$value2 = array("field3" => "value3", "field4" => "value4");
$this->_driver->set(array($id2 => $value2), array("tag2", "tag3"), 84600);
- $id3 = md5(rand());
+ $id3 = random::hash();
$value3 = array("field5" => "value5", "field6" => "value6");
$this->_driver->set(array($id3 => $value3), array("tag3", "tag4"), 84600);
@@ -86,15 +86,15 @@ class Cache_Test extends Gallery_Unit_Test_Case {
}
public function cache_delete_id_test() {
- $id1 = md5(rand());
+ $id1 = random::hash();
$value1 = array("field1" => "value1", "field2" => "value2");
$this->_driver->set(array($id1 => $value1), array("tag1", "tag2"), 84600);
- $id2 = md5(rand());
+ $id2 = random::hash();
$value2 = array("field3" => "value3", "field4" => "value4");
$this->_driver->set(array($id2 => $value2), array("tag2", "tag3"), 846000);
- $id3 = md5(rand());
+ $id3 = random::hash();
$value3 = array("field5" => "value5", "field6" => "value6");
$this->_driver->set(array($id3 => $value3), array("tag3", "tag4"), 84600);
@@ -106,15 +106,15 @@ class Cache_Test extends Gallery_Unit_Test_Case {
}
public function cache_delete_tag_test() {
- $id1 = md5(rand());
+ $id1 = random::hash();
$value1 = array("field1" => "value1", "field2" => "value2");
$this->_driver->set(array($id1 => $value1), array("tag1", "tag2"), 84600);
- $id2 = md5(rand());
+ $id2 = random::hash();
$value2 = array("field3" => "value3", "field4" => "value4");
$this->_driver->set(array($id2 => $value2), array("tag2", "tag3"), 846000);
- $id3 = md5(rand());
+ $id3 = random::hash();
$value3 = array("field5" => "value5", "field6" => "value6");
$this->_driver->set(array($id3 => $value3), array("tag3", "tag4"), 84600);
@@ -126,15 +126,15 @@ class Cache_Test extends Gallery_Unit_Test_Case {
}
public function cache_delete_all_test() {
- $id1 = md5(rand());
+ $id1 = random::hash();
$value1 = array("field1" => "value1", "field2" => "value2");
$this->_driver->set(array($id1 => $value1), array("tag1", "tag2"), 84600);
- $id2 = md5(rand());
+ $id2 = random::hash();
$value2 = array("field3" => "value3", "field4" => "value4");
$this->_driver->set(array($id2 => $value2), array("tag2", "tag3"), 846000);
- $id3 = md5(rand());
+ $id3 = random::hash();
$value3 = array("field5" => "value5", "field6" => "value6");
$this->_driver->set(array($id3 => $value3), array("tag3", "tag4"), 84600);
diff --git a/modules/gallery/tests/Item_Helper_Test.php b/modules/gallery/tests/Item_Helper_Test.php
index eb2458cb..42acfb18 100644
--- a/modules/gallery/tests/Item_Helper_Test.php
+++ b/modules/gallery/tests/Item_Helper_Test.php
@@ -92,7 +92,7 @@ class Item_Helper_Test extends Gallery_Unit_Test_Case {
}
public function move_conflicts_result_in_a_rename_test() {
- $rand = rand();
+ $rand = random::int();
$photo1 = test::random_photo_unsaved(item::root());
$photo1->name = "{$rand}.jpg";
$photo1->slug = (string)$rand;
@@ -125,4 +125,110 @@ class Item_Helper_Test extends Gallery_Unit_Test_Case {
$this->assert_same($photo2->id, $album->album_cover_item_id);
$this->assert_same($photo2->id, $parent->album_cover_item_id);
}
+
+ public function find_by_path_test() {
+ $level1 = test::random_album();
+ $level2 = test::random_album_unsaved($level1);
+ $level2->name = "plus + space";
+ $level2->save()->reload();
+
+ $level3 = test::random_photo_unsaved($level2);
+ $level3->name = "same.jpg";
+ $level3->save()->reload();
+
+ $level2b = test::random_album($level1);
+ $level3b = test::random_photo_unsaved($level2b);
+ $level3b->name = "same.jpg";
+ $level3b->save()->reload();
+
+ // Item in album
+ $this->assert_same(
+ $level3->id,
+ item::find_by_path("/{$level1->name}/{$level2->name}/{$level3->name}")->id);
+
+ // Album, ends with a slash
+ $this->assert_same(
+ $level2->id,
+ item::find_by_path("{$level1->name}/{$level2->name}/")->id);
+
+ // Album, ends without a slash
+ $this->assert_same(
+ $level2->id,
+ item::find_by_path("/{$level1->name}/{$level2->name}")->id);
+
+ // Return root if "" is passed
+ $this->assert_same(item::root()->id, item::find_by_path("")->id);
+
+ // Verify that we don't get confused by the part names, using the fallback code.
+ db::build()
+ ->update("items")
+ ->set(array("relative_path_cache" => null))
+ ->where("id", "IN", array($level3->id, $level3b->id))
+ ->execute();
+ $this->assert_same(
+ $level3->id,
+ item::find_by_path("{$level1->name}/{$level2->name}/{$level3->name}")->id);
+
+ $this->assert_same(
+ $level3b->id,
+ item::find_by_path("{$level1->name}/{$level2b->name}/{$level3b->name}")->id);
+
+ // Verify that we don't get false positives
+ $this->assert_false(
+ item::find_by_path("foo/bar/baz")->loaded());
+
+ // Verify that the fallback code works
+ $this->assert_same(
+ $level3b->id,
+ item::find_by_path("{$level1->name}/{$level2b->name}/{$level3b->name}")->id);
+ }
+
+ public function find_by_relative_url_test() {
+ $level1 = test::random_album();
+ $level2 = test::random_album($level1);
+ $level3 = test::random_photo_unsaved($level2);
+ $level3->slug = "same";
+ $level3->save()->reload();
+
+ $level2b = test::random_album($level1);
+ $level3b = test::random_photo_unsaved($level2b);
+ $level3b->slug = "same";
+ $level3b->save()->reload();
+
+ // Item in album
+ $this->assert_same(
+ $level3->id,
+ item::find_by_relative_url("{$level1->slug}/{$level2->slug}/{$level3->slug}")->id);
+
+ // Album, ends without a slash
+ $this->assert_same(
+ $level2->id,
+ item::find_by_relative_url("{$level1->slug}/{$level2->slug}")->id);
+
+ // Return root if "" is passed
+ $this->assert_same(item::root()->id, item::find_by_relative_url("")->id);
+
+ // Verify that we don't get confused by the part slugs, using the fallback code.
+ db::build()
+ ->update("items")
+ ->set(array("relative_url_cache" => null))
+ ->where("id", "IN", array($level3->id, $level3b->id))
+ ->execute();
+ $this->assert_same(
+ $level3->id,
+ item::find_by_relative_url("{$level1->slug}/{$level2->slug}/{$level3->slug}")->id);
+
+ $this->assert_same(
+ $level3b->id,
+ item::find_by_relative_url("{$level1->slug}/{$level2b->slug}/{$level3b->slug}")->id);
+
+ // Verify that we don't get false positives
+ $this->assert_false(
+ item::find_by_relative_url("foo/bar/baz")->loaded());
+
+ // Verify that the fallback code works
+ $this->assert_same(
+ $level3b->id,
+ item::find_by_relative_url("{$level1->slug}/{$level2b->slug}/{$level3b->slug}")->id);
+ }
}
diff --git a/modules/gallery/tests/Item_Model_Test.php b/modules/gallery/tests/Item_Model_Test.php
index 264a2128..4987d2f9 100644
--- a/modules/gallery/tests/Item_Model_Test.php
+++ b/modules/gallery/tests/Item_Model_Test.php
@@ -278,10 +278,10 @@ class Item_Model_Test extends Gallery_Unit_Test_Case {
public function basic_validation_test() {
$item = ORM::factory("item");
- $item->album_cover_item_id = rand(); // invalid
+ $item->album_cover_item_id = random::int(); // invalid
$item->description = str_repeat("x", 70000); // invalid
$item->name = null;
- $item->parent_id = rand();
+ $item->parent_id = random::int();
$item->slug = null;
$item->sort_column = "bogus";
$item->sort_order = "bogus";
@@ -411,24 +411,47 @@ class Item_Model_Test extends Gallery_Unit_Test_Case {
public function urls_test() {
$photo = test::random_photo();
$this->assert_true(
- preg_match("|http://./var/resizes/name_\d+\.jpg\?m=\d+|", $photo->resize_url()),
+ preg_match("|http://./var/resizes/name_\w+\.jpg\?m=\d+|", $photo->resize_url()),
$photo->resize_url() . " is malformed");
$this->assert_true(
- preg_match("|http://./var/thumbs/name_\d+\.jpg\?m=\d+|", $photo->thumb_url()),
+ preg_match("|http://./var/thumbs/name_\w+\.jpg\?m=\d+|", $photo->thumb_url()),
$photo->thumb_url() . " is malformed");
$this->assert_true(
- preg_match("|http://./var/albums/name_\d+\.jpg\?m=\d+|", $photo->file_url()),
+ preg_match("|http://./var/albums/name_\w+\.jpg\?m=\d+|", $photo->file_url()),
$photo->file_url() . " is malformed");
// Albums have special thumbnails. Empty album has cachebuster of 0 since it has no thumbnail
$album = test::random_album();
$this->assert_true(
- preg_match("|http://./var/thumbs/name_\d+/\.album\.jpg\?m=0|", $album->thumb_url()),
+ preg_match("|http://./var/thumbs/name_\w+/\.album\.jpg\?m=0|", $album->thumb_url()),
$album->thumb_url() . " is malformed");
$photo = test::random_photo($album);
$this->assert_true(
- preg_match("|http://./var/thumbs/name_\d+/\.album\.jpg\?m=\d+|", $album->thumb_url()),
+ preg_match("|http://./var/thumbs/name_\w+/\.album\.jpg\?m=\d+|", $album->thumb_url()),
$album->thumb_url() . " is malformed");
}
+
+ public function legal_extension_test() {
+ foreach (array("test.gif", "test.GIF", "test.Gif", "test.jpeg", "test.JPG") as $name) {
+ $photo = test::random_photo_unsaved(item::root());
+ $photo->name = $name;
+ $photo->save();
+ }
+ }
+
+ public function illegal_extension_test() {
+ foreach (array("test.php", "test.PHP", "test.php5", "test.php4", "test.pl") as $name) {
+ try {
+ $photo = test::random_photo_unsaved(item::root());
+ $photo->name = $name;
+ $photo->save();
+ } catch (ORM_Validation_Exception $e) {
+ $this->assert_equal(array("name" => "illegal_data_file_extension"),
+ $e->validation->errors());
+ continue;
+ }
+ $this->assert_true(false, "Shouldn't get here");
+ }
+ }
}
diff --git a/modules/gallery/tests/Items_Rest_Helper_Test.php b/modules/gallery/tests/Items_Rest_Helper_Test.php
index 8e53110a..49e77876 100644
--- a/modules/gallery/tests/Items_Rest_Helper_Test.php
+++ b/modules/gallery/tests/Items_Rest_Helper_Test.php
@@ -65,21 +65,21 @@ class Items_Rest_Helper_Test extends Gallery_Unit_Test_Case {
$request = new stdClass();
$request->params = new stdClass();
$request->params->urls = json_encode(array(
- rest::url("item", $photo1),
- rest::url("item", $album2)));
+ rest::url("item", $photo2),
+ rest::url("item", $album1)));
$request->params->type = "album";
$this->assert_equal_array(
array(
- array("url" => rest::url("item", $album2),
- "entity" => $album2->as_restful_array(),
+ array("url" => rest::url("item", $album1),
+ "entity" => $album1->as_restful_array(),
"relationships" => array(
"comments" => array(
- "url" => rest::url("item_comments", $album2)),
+ "url" => rest::url("item_comments", $album1)),
"tags" => array(
- "url" => rest::url("item_tags", $album2),
+ "url" => rest::url("item_tags", $album1),
"members" => array())),
"members" => array(
- rest::url("item", $photo2)))),
+ rest::url("item", $album2)))),
items_rest::get($request));
}
diff --git a/modules/gallery/tests/xss_data.txt b/modules/gallery/tests/xss_data.txt
index 0345df96..7c5e803d 100644
--- a/modules/gallery/tests/xss_data.txt
+++ b/modules/gallery/tests/xss_data.txt
@@ -43,8 +43,8 @@ modules/digibug/views/digibug_form.html.php 6 DIRTY form::
modules/exif/views/exif_dialog.html.php 14 DIRTY $details[$i]["caption"]
modules/exif/views/exif_dialog.html.php 21 DIRTY $details[$i]["caption"]
modules/g2_import/views/admin_g2_import.html.php 9 DIRTY $form
-modules/gallery/views/admin_advanced_settings.html.php 20 DIRTY_ATTR text::alternate("g-odd","g-even")
-modules/gallery/views/admin_advanced_settings.html.php 21 DIRTY $var->module_name
+modules/gallery/views/admin_advanced_settings.html.php 21 DIRTY_ATTR text::alternate("g-odd","g-even")
+modules/gallery/views/admin_advanced_settings.html.php 22 DIRTY $var->module_name
modules/gallery/views/admin_block_log_entries.html.php 4 DIRTY_ATTR log::severity_class($entry->severity)
modules/gallery/views/admin_block_log_entries.html.php 8 DIRTY_JS user_profile::url($entry->user->id)
modules/gallery/views/admin_block_log_entries.html.php 10 DIRTY gallery::date_time($entry->timestamp)
@@ -260,8 +260,8 @@ modules/gallery/views/upgrader.html.php 123 DIRTY_ATTR $don
modules/gallery/views/user_languages_block.html.php 2 DIRTY form::dropdown("g-select-session-locale",$installed_locales,$selected)
modules/gallery/views/user_profile.html.php 34 DIRTY_ATTR $user->avatar_url(40,$theme->url(,true))
modules/gallery/views/user_profile.html.php 43 DIRTY $info->view
-modules/image_block/views/image_block_block.html.php 3 DIRTY_JS $item->url()
-modules/image_block/views/image_block_block.html.php 4 DIRTY $item->thumb_img(array("class"=>"g-thumbnail"))
+modules/image_block/views/image_block_block.html.php 4 DIRTY_JS $item->url()
+modules/image_block/views/image_block_block.html.php 5 DIRTY $item->thumb_img(array("class"=>"g-thumbnail"))
modules/info/views/info_block.html.php 22 DIRTY gallery::date_time($item->captured)
modules/info/views/info_block.html.php 29 DIRTY_JS $item->owner->url
modules/notification/views/comment_published.html.php 28 DIRTY_JS $comment->item()->abs_url()
diff --git a/modules/gallery/views/form_uploadify.html.php b/modules/gallery/views/form_uploadify.html.php
index 893bb3b9..77b6d493 100644
--- a/modules/gallery/views/form_uploadify.html.php
+++ b/modules/gallery/views/form_uploadify.html.php
@@ -112,7 +112,7 @@
</script>
<div class="requires-flash">
- <? if ($suhosin_session_encrypt || !$movies_allowed): ?>
+ <? if ($suhosin_session_encrypt || (identity::active_user()->admin && !$movies_allowed)): ?>
<div class="g-message-block g-info">
<? if ($suhosin_session_encrypt): ?>
<p class="g-error">
@@ -122,7 +122,7 @@
</p>
<? endif ?>
- <? if (!$movies_allowed): ?>
+ <? if (identity::active_user()->admin && !$movies_allowed): ?>
<p class="g-warning">
<?= t("Can't find <i>ffmpeg</i> on your system. Movie uploading disabled. <a href=\"%help_url\">Help!</a>", array("help_url" => "http://codex.gallery2.org/Gallery3:FAQ#Why_does_it_say_I.27m_missing_ffmpeg.3F")) ?>
</p>
diff --git a/modules/gallery_unit_test/controllers/gallery_unit_test.php b/modules/gallery_unit_test/controllers/gallery_unit_test.php
index c4a891ba..e241e1dd 100644
--- a/modules/gallery_unit_test/controllers/gallery_unit_test.php
+++ b/modules/gallery_unit_test/controllers/gallery_unit_test.php
@@ -132,7 +132,6 @@ class Gallery_Unit_Test_Controller extends Controller {
graphics::choose_default_toolkit();
$filter = count($_SERVER["argv"]) > 2 ? $_SERVER["argv"][2] : null;
- set_time_limit(300);
print new Unit_Test($modules, $filter);
} catch (ORM_Validation_Exception $e) {
print "Validation Exception: {$e->getMessage()}\n";
diff --git a/modules/gallery_unit_test/helpers/test.php b/modules/gallery_unit_test/helpers/test.php
index 1be82a74..65c7f6b4 100644
--- a/modules/gallery_unit_test/helpers/test.php
+++ b/modules/gallery_unit_test/helpers/test.php
@@ -19,7 +19,7 @@
*/
class test_Core {
static function random_album_unsaved($parent=null) {
- $rand = rand();
+ $rand = random::string(6);
$album = ORM::factory("item");
$album->type = "album";
@@ -34,7 +34,7 @@ class test_Core {
}
static function random_photo_unsaved($parent=null) {
- $rand = rand();
+ $rand = random::string(6);
$photo = ORM::factory("item");
$photo->type = "photo";
$photo->parent_id = $parent ? $parent->id : 1;
@@ -49,16 +49,16 @@ class test_Core {
}
static function random_user($password="password") {
- $rand = "name_" . rand();
+ $rand = "name_" . random::string(6);
return identity::create_user($rand, $rand, $password, "$rand@rand.com");
}
static function random_group() {
- return identity::create_group((string)rand());
+ return identity::create_group(random::string(6));
}
static function random_name($item=null) {
- $rand = "name_" . rand();
+ $rand = "name_" . random::string(6);
if ($item && $item->is_photo()) {
$rand .= ".jpg";
}
@@ -77,7 +77,7 @@ class test_Core {
static function random_tag() {
$tag = ORM::factory("tag");
- $tag->name = (string)rand();
+ $tag->name = random::string(6);
// Reload so that ORM coerces all fields into strings.
return $tag->save()->reload();
diff --git a/modules/image_block/helpers/image_block_installer.php b/modules/image_block/helpers/image_block_installer.php
index 62c38ba4..27097216 100644
--- a/modules/image_block/helpers/image_block_installer.php
+++ b/modules/image_block/helpers/image_block_installer.php
@@ -21,7 +21,7 @@ class image_block_installer {
static function install() {
module::set_var("image_block", "image_count", "1");
- module::set_version("image_block", $version = 2);
+ module::set_version("image_block", $version = 3);
}
static function upgrade($version) {
@@ -30,5 +30,15 @@ class image_block_installer {
module::set_var("image_block", "image_count", "1");
module::set_version("image_block", $version = 2);
}
+
+ // Oops, there was a bug in the installer for version 2 resulting
+ // in some folks not getting the image_count variable set. Bump
+ // to version 3 and fix it.
+ if ($version == 2) {
+ if (module::get_var("image_block", "image_count", 0) === 0) {
+ module::set_var("image_block", "image_count", "1");
+ }
+ module::set_version("image_block", $version = 3);
+ }
}
}
diff --git a/modules/image_block/module.info b/modules/image_block/module.info
index b92b83df..6836fabc 100644
--- a/modules/image_block/module.info
+++ b/modules/image_block/module.info
@@ -1,3 +1,3 @@
name = "Image Block"
description = "Display a random image in the sidebar"
-version = 2
+version = 3
diff --git a/modules/rest/helpers/rest.php b/modules/rest/helpers/rest.php
index 58943700..676c10c3 100644
--- a/modules/rest/helpers/rest.php
+++ b/modules/rest/helpers/rest.php
@@ -54,6 +54,11 @@ class rest_Core {
$html = t("Empty response");
}
print "<pre>$html</pre>";
+ if (Session::instance()->get("profiler", false)) {
+ Profiler::enable();
+ $profiler = new Profiler();
+ $profiler->render();
+ }
break;
default:
@@ -104,7 +109,7 @@ class rest_Core {
if (!$key->loaded()) {
$key->user_id = identity::active_user()->id;
- $key->access_key = md5(md5(uniqid(mt_rand(), true) . access::private_key()));
+ $key->access_key = md5(random::hash() . access::private_key());
$key->save();
}
diff --git a/modules/rest/helpers/rest_event.php b/modules/rest/helpers/rest_event.php
index d8c69e94..9e241bd0 100644
--- a/modules/rest/helpers/rest_event.php
+++ b/modules/rest/helpers/rest_event.php
@@ -43,7 +43,7 @@ class rest_event {
static function user_add_form_admin_completed($user, $form) {
$key = ORM::factory("user_access_key");
$key->user_id = $user->id;
- $key->access_key = md5($user->name . rand());
+ $key->access_key = random::hash($user->name);
$key->save();
}
@@ -64,7 +64,7 @@ class rest_event {
if (!$key->loaded()) {
$key->user_id = $user->id;
- $key->access_key = md5($user->name . rand());
+ $key->access_key = random::hash($user->name);
$key->save();
}
@@ -93,7 +93,7 @@ class rest_event {
if (!$key->loaded()) {
$key->user_id = $data->user->id;
- $key->access_key = md5($data->user->name . rand());
+ $key->access_key = random::hash($data->user->name);
$key->save();
}
$view->rest_key = $key->access_key;
diff --git a/modules/unit_test/libraries/Unit_Test.php b/modules/unit_test/libraries/Unit_Test.php
index 46a926d8..253d6fb6 100644
--- a/modules/unit_test/libraries/Unit_Test.php
+++ b/modules/unit_test/libraries/Unit_Test.php
@@ -185,6 +185,8 @@ class Unit_Test_Core {
$e = null;
try {
+ // Enforce a time limit
+ set_time_limit(30);
// Run the actual test
$object->$method_name();
diff --git a/modules/user/controllers/password.php b/modules/user/controllers/password.php
index 2e5eac5f..567e56dc 100644
--- a/modules/user/controllers/password.php
+++ b/modules/user/controllers/password.php
@@ -51,7 +51,7 @@ class Password_Controller extends Controller {
$user_name = $form->reset->inputs["name"]->value;
$user = user::lookup_by_name($user_name);
if ($user && !empty($user->email)) {
- $user->hash = md5(uniqid(mt_rand(), true));
+ $user->hash = random::hash();
$user->save();
$message = new View("reset_password.html");
$message->confirm_url = url::abs_site("password/do_reset?key=$user->hash");
diff --git a/modules/user/models/group.php b/modules/user/models/group.php
index 17d9320b..8f8e218d 100644
--- a/modules/user/models/group.php
+++ b/modules/user/models/group.php
@@ -19,6 +19,7 @@
*/
class Group_Model_Core extends ORM implements Group_Definition {
protected $has_and_belongs_to_many = array("users");
+ protected $users_cache = null;
/**
* @see ORM::delete()
@@ -28,10 +29,14 @@ class Group_Model_Core extends ORM implements Group_Definition {
module::event("group_before_delete", $this);
parent::delete($id);
module::event("group_deleted", $old);
+ $this->users_cache = null;
}
public function users() {
- return $this->users->find_all();
+ if (!$this->users_cache) {
+ $this->users_cache = $this->users->find_all()->as_array();
+ }
+ return $this->users_cache;
}
/**
@@ -60,6 +65,7 @@ class Group_Model_Core extends ORM implements Group_Definition {
module::event("group_updated", $original, $this);
}
+ $this->users_cache = null;
return $this;
}
diff --git a/modules/user/models/user.php b/modules/user/models/user.php
index 55bb3d6a..585f4b96 100644
--- a/modules/user/models/user.php
+++ b/modules/user/models/user.php
@@ -20,6 +20,7 @@
class User_Model_Core extends ORM implements User_Definition {
protected $has_and_belongs_to_many = array("groups");
protected $password_length = null;
+ protected $groups_cache = null;
public function __set($column, $value) {
switch ($column) {
@@ -43,6 +44,7 @@ class User_Model_Core extends ORM implements User_Definition {
module::event("user_before_delete", $this);
parent::delete($id);
module::event("user_deleted", $old);
+ $this->groups_cache = null;
}
/**
@@ -56,7 +58,10 @@ class User_Model_Core extends ORM implements User_Definition {
}
public function groups() {
- return $this->groups->find_all();
+ if (!$this->groups_cache) {
+ $this->groups_cache = $this->groups->find_all()->as_array();
+ }
+ return $this->groups_cache;
}
/**
@@ -108,6 +113,7 @@ class User_Model_Core extends ORM implements User_Definition {
module::event("user_updated", $original, $this);
}
+ $this->groups_cache = null;
return $this;
}
diff --git a/themes/admin_wind/css/screen.css b/themes/admin_wind/css/screen.css
index 273ac116..7d491cb7 100644
--- a/themes/admin_wind/css/screen.css
+++ b/themes/admin_wind/css/screen.css
@@ -759,7 +759,7 @@ form .g-error {
}
.g-loading-small {
- background: #e8e8e8 url('..lib/images/loading-small.gif') no-repeat center center !important;
+ background: #e8e8e8 url('../images/loading-small.gif') no-repeat center center !important;
}
/** *******************************************************************