Added Kohana v3.0.8
This commit is contained in:
3
includes/kohana/system/classes/arr.php
Normal file
3
includes/kohana/system/classes/arr.php
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
class Arr extends Kohana_Arr {}
|
3
includes/kohana/system/classes/cli.php
Normal file
3
includes/kohana/system/classes/cli.php
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
class CLI extends Kohana_CLI {}
|
3
includes/kohana/system/classes/controller.php
Normal file
3
includes/kohana/system/classes/controller.php
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
abstract class Controller extends Kohana_Controller {}
|
3
includes/kohana/system/classes/controller/rest.php
Normal file
3
includes/kohana/system/classes/controller/rest.php
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
abstract class Controller_REST extends Kohana_Controller_REST {}
|
3
includes/kohana/system/classes/controller/template.php
Normal file
3
includes/kohana/system/classes/controller/template.php
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
abstract class Controller_Template extends Kohana_Controller_Template {}
|
3
includes/kohana/system/classes/cookie.php
Normal file
3
includes/kohana/system/classes/cookie.php
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
class Cookie extends Kohana_Cookie {}
|
3
includes/kohana/system/classes/date.php
Normal file
3
includes/kohana/system/classes/date.php
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
class Date extends Kohana_Date {}
|
3
includes/kohana/system/classes/encrypt.php
Normal file
3
includes/kohana/system/classes/encrypt.php
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
class Encrypt extends Kohana_Encrypt {}
|
3
includes/kohana/system/classes/feed.php
Normal file
3
includes/kohana/system/classes/feed.php
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
class Feed extends Kohana_Feed {}
|
3
includes/kohana/system/classes/file.php
Normal file
3
includes/kohana/system/classes/file.php
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
class File extends Kohana_File {}
|
3
includes/kohana/system/classes/form.php
Normal file
3
includes/kohana/system/classes/form.php
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
class Form extends Kohana_Form {}
|
3
includes/kohana/system/classes/fragment.php
Normal file
3
includes/kohana/system/classes/fragment.php
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
class Fragment extends Kohana_Fragment {}
|
3
includes/kohana/system/classes/html.php
Normal file
3
includes/kohana/system/classes/html.php
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
class HTML extends Kohana_HTML {}
|
3
includes/kohana/system/classes/i18n.php
Normal file
3
includes/kohana/system/classes/i18n.php
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
class I18n extends Kohana_I18n {}
|
3
includes/kohana/system/classes/inflector.php
Normal file
3
includes/kohana/system/classes/inflector.php
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
class Inflector extends Kohana_Inflector {}
|
3
includes/kohana/system/classes/kohana.php
Normal file
3
includes/kohana/system/classes/kohana.php
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
class Kohana extends Kohana_Core {}
|
470
includes/kohana/system/classes/kohana/arr.php
Normal file
470
includes/kohana/system/classes/kohana/arr.php
Normal file
@@ -0,0 +1,470 @@
|
||||
<?php defined('SYSPATH') or die('No direct access allowed.');
|
||||
/**
|
||||
* Array helper.
|
||||
*
|
||||
* @package Kohana
|
||||
* @category Helpers
|
||||
* @author Kohana Team
|
||||
* @copyright (c) 2007-2009 Kohana Team
|
||||
* @license http://kohanaphp.com/license
|
||||
*/
|
||||
class Kohana_Arr {
|
||||
|
||||
/**
|
||||
* @var string default delimiter for path()
|
||||
*/
|
||||
public static $delimiter = '.';
|
||||
|
||||
/**
|
||||
* Tests if an array is associative or not.
|
||||
*
|
||||
* // Returns TRUE
|
||||
* Arr::is_assoc(array('username' => 'john.doe'));
|
||||
*
|
||||
* // Returns FALSE
|
||||
* Arr::is_assoc('foo', 'bar');
|
||||
*
|
||||
* @param array array to check
|
||||
* @return boolean
|
||||
*/
|
||||
public static function is_assoc(array $array)
|
||||
{
|
||||
// Keys of the array
|
||||
$keys = array_keys($array);
|
||||
|
||||
// If the array keys of the keys match the keys, then the array must
|
||||
// not be associative (e.g. the keys array looked like {0:0, 1:1...}).
|
||||
return array_keys($keys) !== $keys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a value from an array using a dot separated path.
|
||||
*
|
||||
* // Get the value of $array['foo']['bar']
|
||||
* $value = Arr::path($array, 'foo.bar');
|
||||
*
|
||||
* Using a wildcard "*" will search intermediate arrays and return an array.
|
||||
*
|
||||
* // Get the values of "color" in theme
|
||||
* $colors = Arr::path($array, 'theme.*.color');
|
||||
*
|
||||
* @param array array to search
|
||||
* @param string key path, delimiter separated
|
||||
* @param mixed default value if the path is not set
|
||||
* @param string key path delimiter
|
||||
* @return mixed
|
||||
*/
|
||||
public static function path($array, $path, $default = NULL, $delimiter = NULL)
|
||||
{
|
||||
if (array_key_exists($path, $array))
|
||||
{
|
||||
// No need to do extra processing
|
||||
return $array[$path];
|
||||
}
|
||||
|
||||
if ($delimiter === NULL)
|
||||
{
|
||||
// Use the default delimiter
|
||||
$delimiter = Arr::$delimiter;
|
||||
}
|
||||
|
||||
// Remove outer delimiters, wildcards, or spaces
|
||||
$path = trim($path, "{$delimiter}* ");
|
||||
|
||||
// Split the keys by delimiter
|
||||
$keys = explode($delimiter, $path);
|
||||
|
||||
do
|
||||
{
|
||||
$key = array_shift($keys);
|
||||
|
||||
if (ctype_digit($key))
|
||||
{
|
||||
// Make the key an integer
|
||||
$key = (int) $key;
|
||||
}
|
||||
|
||||
if (isset($array[$key]))
|
||||
{
|
||||
if ($keys)
|
||||
{
|
||||
if (is_array($array[$key]))
|
||||
{
|
||||
// Dig down into the next part of the path
|
||||
$array = $array[$key];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Unable to dig deeper
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Found the path requested
|
||||
return $array[$key];
|
||||
}
|
||||
}
|
||||
elseif ($key === '*')
|
||||
{
|
||||
// Handle wildcards
|
||||
|
||||
$values = array();
|
||||
foreach ($array as $arr)
|
||||
{
|
||||
if ($value = Arr::path($arr, implode('.', $keys)))
|
||||
{
|
||||
$values[] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
if ($values)
|
||||
{
|
||||
// Found the values requested
|
||||
return $values;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Unable to dig deeper
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Unable to dig deeper
|
||||
break;
|
||||
}
|
||||
}
|
||||
while ($keys);
|
||||
|
||||
// Unable to find the value requested
|
||||
return $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill an array with a range of numbers.
|
||||
*
|
||||
* // Fill an array with values 5, 10, 15, 20
|
||||
* $values = Arr::range(5, 20);
|
||||
*
|
||||
* @param integer stepping
|
||||
* @param integer ending number
|
||||
* @return array
|
||||
*/
|
||||
public static function range($step = 10, $max = 100)
|
||||
{
|
||||
if ($step < 1)
|
||||
return array();
|
||||
|
||||
$array = array();
|
||||
for ($i = $step; $i <= $max; $i += $step)
|
||||
{
|
||||
$array[$i] = $i;
|
||||
}
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a single key from an array. If the key does not exist in the
|
||||
* array, the default value will be returned instead.
|
||||
*
|
||||
* // Get the value "username" from $_POST, if it exists
|
||||
* $username = Arr::get($_POST, 'username');
|
||||
*
|
||||
* // Get the value "sorting" from $_GET, if it exists
|
||||
* $sorting = Arr::get($_GET, 'sorting');
|
||||
*
|
||||
* @param array array to extract from
|
||||
* @param string key name
|
||||
* @param mixed default value
|
||||
* @return mixed
|
||||
*/
|
||||
public static function get($array, $key, $default = NULL)
|
||||
{
|
||||
return isset($array[$key]) ? $array[$key] : $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves multiple keys from an array. If the key does not exist in the
|
||||
* array, the default value will be added instead.
|
||||
*
|
||||
* // Get the values "username", "password" from $_POST
|
||||
* $auth = Arr::extract($_POST, array('username', 'password'));
|
||||
*
|
||||
* @param array array to extract keys from
|
||||
* @param array list of key names
|
||||
* @param mixed default value
|
||||
* @return array
|
||||
*/
|
||||
public static function extract($array, array $keys, $default = NULL)
|
||||
{
|
||||
$found = array();
|
||||
foreach ($keys as $key)
|
||||
{
|
||||
$found[$key] = isset($array[$key]) ? $array[$key] : $default;
|
||||
}
|
||||
|
||||
return $found;
|
||||
}
|
||||
|
||||
/**
|
||||
* Binary search algorithm.
|
||||
*
|
||||
* @deprecated Use [array_search](http://php.net/array_search) instead
|
||||
*
|
||||
* @param mixed the value to search for
|
||||
* @param array an array of values to search in
|
||||
* @param boolean sort the array now
|
||||
* @return integer the index of the match
|
||||
* @return FALSE no matching index found
|
||||
*/
|
||||
public static function binary_search($needle, $haystack, $sort = FALSE)
|
||||
{
|
||||
return array_search($needle, $haystack);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a value to the beginning of an associative array.
|
||||
*
|
||||
* // Add an empty value to the start of a select list
|
||||
* Arr::unshift_assoc($array, 'none', 'Select a value');
|
||||
*
|
||||
* @param array array to modify
|
||||
* @param string array key name
|
||||
* @param mixed array value
|
||||
* @return array
|
||||
*/
|
||||
public static function unshift( array & $array, $key, $val)
|
||||
{
|
||||
$array = array_reverse($array, TRUE);
|
||||
$array[$key] = $val;
|
||||
$array = array_reverse($array, TRUE);
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursive version of [array_map](http://php.net/array_map), applies the
|
||||
* same callback to all elements in an array, including sub-arrays.
|
||||
*
|
||||
* // Apply "strip_tags" to every element in the array
|
||||
* $array = Arr::map('strip_tags', $array);
|
||||
*
|
||||
* [!!] Unlike `array_map`, this method requires a callback and will only map
|
||||
* a single array.
|
||||
*
|
||||
* @param mixed callback applied to every element in the array
|
||||
* @param array array to map
|
||||
* @return array
|
||||
*/
|
||||
public static function map($callback, $array)
|
||||
{
|
||||
foreach ($array as $key => $val)
|
||||
{
|
||||
if (is_array($val))
|
||||
{
|
||||
$array[$key] = Arr::map($callback, $val);
|
||||
}
|
||||
else
|
||||
{
|
||||
$array[$key] = call_user_func($callback, $val);
|
||||
}
|
||||
}
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges one or more arrays recursively and preserves all keys.
|
||||
* Note that this does not work the same as [array_merge_recursive](http://php.net/array_merge_recursive)!
|
||||
*
|
||||
* $john = array('name' => 'john', 'children' => array('fred', 'paul', 'sally', 'jane'));
|
||||
* $mary = array('name' => 'mary', 'children' => array('jane'));
|
||||
*
|
||||
* // John and Mary are married, merge them together
|
||||
* $john = Arr::merge($john, $mary);
|
||||
*
|
||||
* // The output of $john will now be:
|
||||
* array('name' => 'mary', 'children' => array('fred', 'paul', 'sally', 'jane'))
|
||||
*
|
||||
* @param array initial array
|
||||
* @param array array to merge
|
||||
* @param array ...
|
||||
* @return array
|
||||
*/
|
||||
public static function merge(array $a1, array $a2)
|
||||
{
|
||||
$result = array();
|
||||
for ($i = 0, $total = func_num_args(); $i < $total; $i++)
|
||||
{
|
||||
// Get the next array
|
||||
$arr = func_get_arg($i);
|
||||
|
||||
// Is the array associative?
|
||||
$assoc = Arr::is_assoc($arr);
|
||||
|
||||
foreach ($arr as $key => $val)
|
||||
{
|
||||
if (isset($result[$key]))
|
||||
{
|
||||
if (is_array($val) && is_array($result[$key]))
|
||||
{
|
||||
if (Arr::is_assoc($val))
|
||||
{
|
||||
// Associative arrays are merged recursively
|
||||
$result[$key] = Arr::merge($result[$key], $val);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Find the values that are not already present
|
||||
$diff = array_diff($val, $result[$key]);
|
||||
|
||||
// Indexed arrays are merged to prevent duplicates
|
||||
$result[$key] = array_merge($result[$key], $diff);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($assoc)
|
||||
{
|
||||
// Associative values are replaced
|
||||
$result[$key] = $val;
|
||||
}
|
||||
elseif ( ! in_array($val, $result, TRUE))
|
||||
{
|
||||
// Indexed values are added only if they do not yet exist
|
||||
$result[] = $val;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// New values are added
|
||||
$result[$key] = $val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwrites an array with values from input arrays.
|
||||
* Keys that do not exist in the first array will not be added!
|
||||
*
|
||||
* $a1 = array('name' => 'john', 'mood' => 'happy', 'food' => 'bacon');
|
||||
* $a2 = array('name' => 'jack', 'food' => 'tacos', 'drink' => 'beer');
|
||||
*
|
||||
* // Overwrite the values of $a1 with $a2
|
||||
* $array = Arr::overwrite($a1, $a2);
|
||||
*
|
||||
* // The output of $array will now be:
|
||||
* array('name' => 'jack', 'mood' => 'happy', 'food' => 'bacon')
|
||||
*
|
||||
* @param array master array
|
||||
* @param array input arrays that will overwrite existing values
|
||||
* @return array
|
||||
*/
|
||||
public static function overwrite($array1, $array2)
|
||||
{
|
||||
foreach (array_intersect_key($array2, $array1) as $key => $value)
|
||||
{
|
||||
$array1[$key] = $value;
|
||||
}
|
||||
|
||||
if (func_num_args() > 2)
|
||||
{
|
||||
foreach (array_slice(func_get_args(), 2) as $array2)
|
||||
{
|
||||
foreach (array_intersect_key($array2, $array1) as $key => $value)
|
||||
{
|
||||
$array1[$key] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $array1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a callable function and parameter list from a string representation.
|
||||
* Note that this function does not validate the callback string.
|
||||
*
|
||||
* // Get the callback function and parameters
|
||||
* list($func, $params) = Arr::callback('Foo::bar(apple,orange)');
|
||||
*
|
||||
* // Get the result of the callback
|
||||
* $result = call_user_func_array($func, $params);
|
||||
*
|
||||
* @param string callback string
|
||||
* @return array function, params
|
||||
*/
|
||||
public static function callback($str)
|
||||
{
|
||||
// Overloaded as parts are found
|
||||
$command = $params = NULL;
|
||||
|
||||
// command[param,param]
|
||||
if (preg_match('/^([^\(]*+)\((.*)\)$/', $str, $match))
|
||||
{
|
||||
// command
|
||||
$command = $match[1];
|
||||
|
||||
if ($match[2] !== '')
|
||||
{
|
||||
// param,param
|
||||
$params = preg_split('/(?<!\\\\),/', $match[2]);
|
||||
$params = str_replace('\,', ',', $params);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// command
|
||||
$command = $str;
|
||||
}
|
||||
|
||||
if (strpos($command, '::') !== FALSE)
|
||||
{
|
||||
// Create a static method callable command
|
||||
$command = explode('::', $command, 2);
|
||||
}
|
||||
|
||||
return array($command, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a multi-dimensional array into a single-dimensional array.
|
||||
*
|
||||
* $array = array('set' => array('one' => 'something'), 'two' => 'other');
|
||||
*
|
||||
* // Flatten the array
|
||||
* $array = Arr::flatten($array);
|
||||
*
|
||||
* // The array will now be
|
||||
* array('one' => 'something', 'two' => 'other');
|
||||
*
|
||||
* [!!] The keys of array values will be discarded.
|
||||
*
|
||||
* @param array array to flatten
|
||||
* @return array
|
||||
* @since 3.0.6
|
||||
*/
|
||||
public static function flatten($array)
|
||||
{
|
||||
$flat = array();
|
||||
foreach ($array as $key => $value)
|
||||
{
|
||||
if (is_array($value))
|
||||
{
|
||||
$flat += Arr::flatten($value);
|
||||
}
|
||||
else
|
||||
{
|
||||
$flat[$key] = $value;
|
||||
}
|
||||
}
|
||||
return $flat;
|
||||
}
|
||||
|
||||
} // End arr
|
75
includes/kohana/system/classes/kohana/cli.php
Normal file
75
includes/kohana/system/classes/kohana/cli.php
Normal file
@@ -0,0 +1,75 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
/**
|
||||
* Helper functions for working in a command-line environment.
|
||||
*
|
||||
* @package Kohana
|
||||
* @category Helpers
|
||||
* @author Kohana Team
|
||||
* @copyright (c) 2009 Kohana Team
|
||||
* @license http://kohanaphp.com/license
|
||||
*/
|
||||
class Kohana_CLI {
|
||||
|
||||
/**
|
||||
* Returns one or more command-line options. Options are specified using
|
||||
* standard CLI syntax:
|
||||
*
|
||||
* php index.php --username=john.smith --password=secret --var="some value with spaces"
|
||||
*
|
||||
* // Get the values of "username" and "password"
|
||||
* $auth = CLI::options('username', 'password');
|
||||
*
|
||||
* @param string option name
|
||||
* @param ...
|
||||
* @return array
|
||||
*/
|
||||
public static function options($options)
|
||||
{
|
||||
// Get all of the requested options
|
||||
$options = func_get_args();
|
||||
|
||||
// Found option values
|
||||
$values = array();
|
||||
|
||||
// Skip the first option, it is always the file executed
|
||||
for ($i = 1; $i < $_SERVER['argc']; $i++)
|
||||
{
|
||||
if ( ! isset($_SERVER['argv'][$i]))
|
||||
{
|
||||
// No more args left
|
||||
break;
|
||||
}
|
||||
|
||||
// Get the option
|
||||
$opt = $_SERVER['argv'][$i];
|
||||
|
||||
if (substr($opt, 0, 2) !== '--')
|
||||
{
|
||||
// This is not an option argument
|
||||
continue;
|
||||
}
|
||||
|
||||
// Remove the "--" prefix
|
||||
$opt = substr($opt, 2);
|
||||
|
||||
if (strpos($opt, '='))
|
||||
{
|
||||
// Separate the name and value
|
||||
list ($opt, $value) = explode('=', $opt, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
$value = NULL;
|
||||
}
|
||||
|
||||
if (in_array($opt, $options))
|
||||
{
|
||||
// Set the given value
|
||||
$values[$opt] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
} // End CLI
|
153
includes/kohana/system/classes/kohana/config.php
Normal file
153
includes/kohana/system/classes/kohana/config.php
Normal file
@@ -0,0 +1,153 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
/**
|
||||
* Wrapper for configuration arrays. Multiple configuration readers can be
|
||||
* attached to allow loading configuration from files, database, etc.
|
||||
*
|
||||
* @package Kohana
|
||||
* @category Configuration
|
||||
* @author Kohana Team
|
||||
* @copyright (c) 2009 Kohana Team
|
||||
* @license http://kohanaphp.com/license
|
||||
*/
|
||||
class Kohana_Config {
|
||||
|
||||
// Singleton static instance
|
||||
protected static $_instance;
|
||||
|
||||
/**
|
||||
* Get the singleton instance of Kohana_Config.
|
||||
*
|
||||
* $config = Kohana_Config::instance();
|
||||
*
|
||||
* @return Kohana_Config
|
||||
*/
|
||||
public static function instance()
|
||||
{
|
||||
if (self::$_instance === NULL)
|
||||
{
|
||||
// Create a new instance
|
||||
self::$_instance = new self;
|
||||
}
|
||||
|
||||
return self::$_instance;
|
||||
}
|
||||
|
||||
// Configuration readers
|
||||
protected $_readers = array();
|
||||
|
||||
/**
|
||||
* Attach a configuration reader. By default, the reader will be added as
|
||||
* the first used reader. However, if the reader should be used only when
|
||||
* all other readers fail, use `FALSE` for the second parameter.
|
||||
*
|
||||
* $config->attach($reader); // Try first
|
||||
* $config->attach($reader, FALSE); // Try last
|
||||
*
|
||||
* @param object Kohana_Config_Reader instance
|
||||
* @param boolean add the reader as the first used object
|
||||
* @return $this
|
||||
*/
|
||||
public function attach(Kohana_Config_Reader $reader, $first = TRUE)
|
||||
{
|
||||
if ($first === TRUE)
|
||||
{
|
||||
// Place the log reader at the top of the stack
|
||||
array_unshift($this->_readers, $reader);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Place the reader at the bottom of the stack
|
||||
$this->_readers[] = $reader;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detach a configuration reader.
|
||||
*
|
||||
* $config->detach($reader);
|
||||
*
|
||||
* @param object Kohana_Config_Reader instance
|
||||
* @return $this
|
||||
*/
|
||||
public function detach(Kohana_Config_Reader $reader)
|
||||
{
|
||||
if (($key = array_search($reader, $this->_readers)) !== FALSE)
|
||||
{
|
||||
// Remove the writer
|
||||
unset($this->_readers[$key]);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a configuration group. Searches the readers in order until the
|
||||
* group is found. If the group does not exist, an empty configuration
|
||||
* array will be loaded using the first reader.
|
||||
*
|
||||
* $array = $config->load($name);
|
||||
*
|
||||
* @param string configuration group name
|
||||
* @return object Kohana_Config_Reader
|
||||
* @throws Kohana_Exception
|
||||
*/
|
||||
public function load($group)
|
||||
{
|
||||
foreach ($this->_readers as $reader)
|
||||
{
|
||||
if ($config = $reader->load($group))
|
||||
{
|
||||
// Found a reader for this configuration group
|
||||
return $config;
|
||||
}
|
||||
}
|
||||
|
||||
// Reset the iterator
|
||||
reset($this->_readers);
|
||||
|
||||
if ( ! is_object($config = current($this->_readers)))
|
||||
{
|
||||
throw new Kohana_Exception('No configuration readers attached');
|
||||
}
|
||||
|
||||
// Load the reader as an empty array
|
||||
return $config->load($group, array());
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy one configuration group to all of the other readers.
|
||||
*
|
||||
* $config->copy($name);
|
||||
*
|
||||
* @param string configuration group name
|
||||
* @return $this
|
||||
*/
|
||||
public function copy($group)
|
||||
{
|
||||
// Load the configuration group
|
||||
$config = $this->load($group);
|
||||
|
||||
foreach ($this->_readers as $reader)
|
||||
{
|
||||
if ($config instanceof $reader)
|
||||
{
|
||||
// Do not copy the config to the same group
|
||||
continue;
|
||||
}
|
||||
|
||||
// Load the configuration object
|
||||
$object = $reader->load($group, array());
|
||||
|
||||
foreach ($config as $key => $value)
|
||||
{
|
||||
// Copy each value in the config
|
||||
$object->offsetSet($key, $value);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
} // End Kohana_Config
|
56
includes/kohana/system/classes/kohana/config/file.php
Normal file
56
includes/kohana/system/classes/kohana/config/file.php
Normal file
@@ -0,0 +1,56 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
/**
|
||||
* File-based configuration reader. Multiple configuration directories can be
|
||||
* used by attaching multiple instances of this class to [Kohana_Config].
|
||||
*
|
||||
* @package Kohana
|
||||
* @category Configuration
|
||||
* @author Kohana Team
|
||||
* @copyright (c) 2009 Kohana Team
|
||||
* @license http://kohanaphp.com/license
|
||||
*/
|
||||
class Kohana_Config_File extends Kohana_Config_Reader {
|
||||
|
||||
// Configuration group name
|
||||
protected $_configuration_group;
|
||||
|
||||
// Has the config group changed?
|
||||
protected $_configuration_modified = FALSE;
|
||||
|
||||
public function __construct($directory = 'config')
|
||||
{
|
||||
// Set the configuration directory name
|
||||
$this->_directory = trim($directory, '/');
|
||||
|
||||
// Load the empty array
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load and merge all of the configuration files in this group.
|
||||
*
|
||||
* $config->load($name);
|
||||
*
|
||||
* @param string configuration group name
|
||||
* @param array configuration array
|
||||
* @return $this clone of the current object
|
||||
* @uses Kohana::load
|
||||
*/
|
||||
public function load($group, array $config = NULL)
|
||||
{
|
||||
if ($files = Kohana::find_file($this->_directory, $group, NULL, TRUE))
|
||||
{
|
||||
// Initialize the config array
|
||||
$config = array();
|
||||
|
||||
foreach ($files as $file)
|
||||
{
|
||||
// Merge each file to the configuration array
|
||||
$config = Arr::merge($config, Kohana::load($file));
|
||||
}
|
||||
}
|
||||
|
||||
return parent::load($group, $config);
|
||||
}
|
||||
|
||||
} // End Kohana_Config
|
113
includes/kohana/system/classes/kohana/config/reader.php
Normal file
113
includes/kohana/system/classes/kohana/config/reader.php
Normal file
@@ -0,0 +1,113 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
/**
|
||||
* Abstract configuration reader. All configuration readers must extend
|
||||
* this class.
|
||||
*
|
||||
* @package Kohana
|
||||
* @category Configuration
|
||||
* @author Kohana Team
|
||||
* @copyright (c) 2008-2009 Kohana Team
|
||||
* @license http://kohanaphp.com/license
|
||||
*/
|
||||
abstract class Kohana_Config_Reader extends ArrayObject {
|
||||
|
||||
// Configuration group name
|
||||
protected $_configuration_group;
|
||||
|
||||
/**
|
||||
* Loads an empty array as the initial configuration and enables array
|
||||
* keys to be used as properties.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct(array(), ArrayObject::ARRAY_AS_PROPS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current group in serialized form.
|
||||
*
|
||||
* echo $config;
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return serialize($this->getArrayCopy());
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a configuration group.
|
||||
*
|
||||
* $config->load($name, $array);
|
||||
*
|
||||
* This method must be extended by all readers. After the group has been
|
||||
* loaded, call `parent::load($group, $config)` for final preparation.
|
||||
*
|
||||
* @param string configuration group name
|
||||
* @param array configuration array
|
||||
* @return $this a clone of this object
|
||||
*/
|
||||
public function load($group, array $config = NULL)
|
||||
{
|
||||
if ($config === NULL)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Clone the current object
|
||||
$object = clone $this;
|
||||
|
||||
// Set the group name
|
||||
$object->_configuration_group = $group;
|
||||
|
||||
// Swap the array with the actual configuration
|
||||
$object->exchangeArray($config);
|
||||
|
||||
return $object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the raw array that is being used for this object.
|
||||
*
|
||||
* $array = $config->as_array();
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function as_array()
|
||||
{
|
||||
return $this->getArrayCopy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a variable from the configuration or return the default value.
|
||||
*
|
||||
* $value = $config->get($key);
|
||||
*
|
||||
* @param string array key
|
||||
* @param mixed default value
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($key, $default = NULL)
|
||||
{
|
||||
return $this->offsetExists($key) ? $this->offsetGet($key) : $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a value in the configuration array.
|
||||
*
|
||||
* $config->set($key, $new_value);
|
||||
*
|
||||
* @param string array key
|
||||
* @param mixed array value
|
||||
* @return $this
|
||||
*/
|
||||
public function set($key, $value)
|
||||
{
|
||||
$this->offsetSet($key, $value);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
} // End Kohana_Config_Reader
|
66
includes/kohana/system/classes/kohana/controller.php
Normal file
66
includes/kohana/system/classes/kohana/controller.php
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
/**
|
||||
* Abstract controller class. Controllers should only be created using a [Request].
|
||||
*
|
||||
* Controllers methods will be automatically called in the following order by
|
||||
* the request:
|
||||
*
|
||||
* $controller = new Controller_Foo($request);
|
||||
* $controller->before();
|
||||
* $controller->action_bar();
|
||||
* $controller->after();
|
||||
*
|
||||
* The controller action should add the output it creates to
|
||||
* `$this->request->response`, typically in the form of a [View], during the
|
||||
* "action" part of execution.
|
||||
*
|
||||
* @package Kohana
|
||||
* @category Controller
|
||||
* @author Kohana Team
|
||||
* @copyright (c) 2008-2009 Kohana Team
|
||||
* @license http://kohanaphp.com/license
|
||||
*/
|
||||
abstract class Kohana_Controller {
|
||||
|
||||
/**
|
||||
* @var object Request that created the controller
|
||||
*/
|
||||
public $request;
|
||||
|
||||
/**
|
||||
* Creates a new controller instance. Each controller must be constructed
|
||||
* with the request object that created it.
|
||||
*
|
||||
* @param object Request that created the controller
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Kohana_Request $request)
|
||||
{
|
||||
// Assign the request to the controller
|
||||
$this->request = $request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Automatically executed before the controller action. Can be used to set
|
||||
* class properties, do authorization checks, and execute other custom code.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function before()
|
||||
{
|
||||
// Nothing by default
|
||||
}
|
||||
|
||||
/**
|
||||
* Automatically executed after the controller action. Can be used to apply
|
||||
* transformation to the request response, add extra output, and execute
|
||||
* other custom code.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function after()
|
||||
{
|
||||
// Nothing by default
|
||||
}
|
||||
|
||||
} // End Controller
|
74
includes/kohana/system/classes/kohana/controller/rest.php
Normal file
74
includes/kohana/system/classes/kohana/controller/rest.php
Normal file
@@ -0,0 +1,74 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
/**
|
||||
* Abstract Controller class for RESTful controller mapping. Supports GET, PUT,
|
||||
* POST, and DELETE. By default, these methods will be mapped to these actions:
|
||||
*
|
||||
* GET
|
||||
* : Mapped to the "index" action, lists all objects
|
||||
*
|
||||
* POST
|
||||
* : Mapped to the "create" action, creates a new object
|
||||
*
|
||||
* PUT
|
||||
* : Mapped to the "update" action, update an existing object
|
||||
*
|
||||
* DELETE
|
||||
* : Mapped to the "delete" action, delete an existing object
|
||||
*
|
||||
* Additional methods can be supported by adding the method and action to
|
||||
* the `$_action_map` property.
|
||||
*
|
||||
* [!!] Using this class within a website will require heavy modification,
|
||||
* due to most web browsers only supporting the GET and POST methods.
|
||||
* Generally, this class should only be used for web services and APIs.
|
||||
*
|
||||
* @package Kohana
|
||||
* @category Controller
|
||||
* @author Kohana Team
|
||||
* @copyright (c) 2009 Kohana Team
|
||||
* @license http://kohanaphp.com/license
|
||||
*/
|
||||
abstract class Kohana_Controller_REST extends Controller {
|
||||
|
||||
protected $_action_map = array
|
||||
(
|
||||
'GET' => 'index',
|
||||
'PUT' => 'update',
|
||||
'POST' => 'create',
|
||||
'DELETE' => 'delete',
|
||||
);
|
||||
|
||||
protected $_action_requested = '';
|
||||
|
||||
/**
|
||||
* Checks the requested method against the available methods. If the method
|
||||
* is supported, sets the request action from the map. If not supported,
|
||||
* the "invalid" action will be called.
|
||||
*/
|
||||
public function before()
|
||||
{
|
||||
$this->_action_requested = $this->request->action;
|
||||
|
||||
if ( ! isset($this->_action_map[Request::$method]))
|
||||
{
|
||||
$this->request->action = 'invalid';
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->request->action = $this->_action_map[Request::$method];
|
||||
}
|
||||
|
||||
return parent::before();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a 405 "Method Not Allowed" response and a list of allowed actions.
|
||||
*/
|
||||
public function action_invalid()
|
||||
{
|
||||
// Send the "Method Not Allowed" response
|
||||
$this->request->status = 405;
|
||||
$this->request->headers['Allow'] = implode(', ', array_keys($this->_action_map));
|
||||
}
|
||||
|
||||
} // End REST
|
@@ -0,0 +1,50 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
/**
|
||||
* Abstract controller class for automatic templating.
|
||||
*
|
||||
* @package Kohana
|
||||
* @category Controller
|
||||
* @author Kohana Team
|
||||
* @copyright (c) 2008-2009 Kohana Team
|
||||
* @license http://kohanaphp.com/license
|
||||
*/
|
||||
abstract class Kohana_Controller_Template extends Controller {
|
||||
|
||||
/**
|
||||
* @var string page template
|
||||
*/
|
||||
public $template = 'template';
|
||||
|
||||
/**
|
||||
* @var boolean auto render template
|
||||
**/
|
||||
public $auto_render = TRUE;
|
||||
|
||||
/**
|
||||
* Loads the template [View] object.
|
||||
*/
|
||||
public function before()
|
||||
{
|
||||
if ($this->auto_render === TRUE)
|
||||
{
|
||||
// Load the template
|
||||
$this->template = View::factory($this->template);
|
||||
}
|
||||
|
||||
return parent::before();
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns the template [View] as the request response.
|
||||
*/
|
||||
public function after()
|
||||
{
|
||||
if ($this->auto_render === TRUE)
|
||||
{
|
||||
$this->request->response = $this->template;
|
||||
}
|
||||
|
||||
return parent::after();
|
||||
}
|
||||
|
||||
} // End Controller_Template
|
155
includes/kohana/system/classes/kohana/cookie.php
Normal file
155
includes/kohana/system/classes/kohana/cookie.php
Normal file
@@ -0,0 +1,155 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
/**
|
||||
* Cookie helper.
|
||||
*
|
||||
* @package Kohana
|
||||
* @category Helpers
|
||||
* @author Kohana Team
|
||||
* @copyright (c) 2008-2009 Kohana Team
|
||||
* @license http://kohanaphp.com/license
|
||||
*/
|
||||
class Kohana_Cookie {
|
||||
|
||||
/**
|
||||
* @var string Magic salt to add to the cookie
|
||||
*/
|
||||
public static $salt = 'kooky';
|
||||
|
||||
/**
|
||||
* @var integer Number of seconds before the cookie expires
|
||||
*/
|
||||
public static $expiration = 0;
|
||||
|
||||
/**
|
||||
* @var string Restrict the path that the cookie is available to
|
||||
*/
|
||||
public static $path = '/';
|
||||
|
||||
/**
|
||||
* @var string Restrict the domain that the cookie is available to
|
||||
*/
|
||||
public static $domain = NULL;
|
||||
|
||||
/**
|
||||
* @var boolean Only transmit cookies over secure connections
|
||||
*/
|
||||
public static $secure = FALSE;
|
||||
|
||||
/**
|
||||
* @var boolean Only transmit cookies over HTTP, disabling Javascript access
|
||||
*/
|
||||
public static $httponly = FALSE;
|
||||
|
||||
/**
|
||||
* Gets the value of a signed cookie. Cookies without signatures will not
|
||||
* be returned. If the cookie signature is present, but invalid, the cookie
|
||||
* will be deleted.
|
||||
*
|
||||
* // Get the "theme" cookie, or use "blue" if the cookie does not exist
|
||||
* $theme = Cookie::get('theme', 'blue');
|
||||
*
|
||||
* @param string cookie name
|
||||
* @param mixed default value to return
|
||||
* @return string
|
||||
*/
|
||||
public static function get($key, $default = NULL)
|
||||
{
|
||||
if ( ! isset($_COOKIE[$key]))
|
||||
{
|
||||
// The cookie does not exist
|
||||
return $default;
|
||||
}
|
||||
|
||||
// Get the cookie value
|
||||
$cookie = $_COOKIE[$key];
|
||||
|
||||
// Find the position of the split between salt and contents
|
||||
$split = strlen(Cookie::salt($key, NULL));
|
||||
|
||||
if (isset($cookie[$split]) AND $cookie[$split] === '~')
|
||||
{
|
||||
// Separate the salt and the value
|
||||
list ($hash, $value) = explode('~', $cookie, 2);
|
||||
|
||||
if (Cookie::salt($key, $value) === $hash)
|
||||
{
|
||||
// Cookie signature is valid
|
||||
return $value;
|
||||
}
|
||||
|
||||
// The cookie signature is invalid, delete it
|
||||
Cookie::delete($key);
|
||||
}
|
||||
|
||||
return $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a signed cookie. Note that all cookie values must be strings and no
|
||||
* automatic serialization will be performed!
|
||||
*
|
||||
* // Set the "theme" cookie
|
||||
* Cookie::set('theme', 'red');
|
||||
*
|
||||
* @param string name of cookie
|
||||
* @param string value of cookie
|
||||
* @param integer lifetime in seconds
|
||||
* @return boolean
|
||||
* @uses Cookie::salt
|
||||
*/
|
||||
public static function set($name, $value, $expiration = NULL)
|
||||
{
|
||||
if ($expiration === NULL)
|
||||
{
|
||||
// Use the default expiration
|
||||
$expiration = Cookie::$expiration;
|
||||
}
|
||||
|
||||
if ($expiration !== 0)
|
||||
{
|
||||
// The expiration is expected to be a UNIX timestamp
|
||||
$expiration += time();
|
||||
}
|
||||
|
||||
// Add the salt to the cookie value
|
||||
$value = Cookie::salt($name, $value).'~'.$value;
|
||||
|
||||
return setcookie($name, $value, $expiration, Cookie::$path, Cookie::$domain, Cookie::$secure, Cookie::$httponly);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a cookie by making the value NULL and expiring it.
|
||||
*
|
||||
* Cookie::delete('theme');
|
||||
*
|
||||
* @param string cookie name
|
||||
* @return boolean
|
||||
* @uses Cookie::set
|
||||
*/
|
||||
public static function delete($name)
|
||||
{
|
||||
// Remove the cookie
|
||||
unset($_COOKIE[$name]);
|
||||
|
||||
// Nullify the cookie and make it expire
|
||||
return Cookie::set($name, NULL, -86400);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a salt string for a cookie based on the name and value.
|
||||
*
|
||||
* $salt = Cookie::salt('theme', 'red');
|
||||
*
|
||||
* @param string name of cookie
|
||||
* @param string value of cookie
|
||||
* @return string
|
||||
*/
|
||||
public static function salt($name, $value)
|
||||
{
|
||||
// Determine the user agent
|
||||
$agent = isset($_SERVER['HTTP_USER_AGENT']) ? strtolower($_SERVER['HTTP_USER_AGENT']) : 'unknown';
|
||||
|
||||
return sha1($agent.$name.$value.Cookie::$salt);
|
||||
}
|
||||
|
||||
} // End cookie
|
1560
includes/kohana/system/classes/kohana/core.php
Normal file
1560
includes/kohana/system/classes/kohana/core.php
Normal file
File diff suppressed because it is too large
Load Diff
557
includes/kohana/system/classes/kohana/date.php
Normal file
557
includes/kohana/system/classes/kohana/date.php
Normal file
@@ -0,0 +1,557 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
/**
|
||||
* Date helper.
|
||||
*
|
||||
* @package Kohana
|
||||
* @category Helpers
|
||||
* @author Kohana Team
|
||||
* @copyright (c) 2007-2009 Kohana Team
|
||||
* @license http://kohanaphp.com/license
|
||||
*/
|
||||
class Kohana_Date {
|
||||
|
||||
// Second amounts for various time increments
|
||||
const YEAR = 31556926;
|
||||
const MONTH = 2629744;
|
||||
const WEEK = 604800;
|
||||
const DAY = 86400;
|
||||
const HOUR = 3600;
|
||||
const MINUTE = 60;
|
||||
|
||||
/**
|
||||
* Default timestamp format for formatted_time
|
||||
* @var string
|
||||
*/
|
||||
public static $timestamp_format = 'Y-m-d H:i:s';
|
||||
|
||||
/**
|
||||
* Timezone for formatted_time
|
||||
* @link http://uk2.php.net/manual/en/timezones.php
|
||||
* @var string
|
||||
*/
|
||||
public static $timezone;
|
||||
|
||||
/**
|
||||
* Returns the offset (in seconds) between two time zones. Use this to
|
||||
* display dates to users in different time zones.
|
||||
*
|
||||
* $seconds = Date::offset('America/Chicago', 'GMT');
|
||||
*
|
||||
* [!!] A list of time zones that PHP supports can be found at
|
||||
* <http://php.net/timezones>.
|
||||
*
|
||||
* @param string timezone that to find the offset of
|
||||
* @param string timezone used as the baseline
|
||||
* @param mixed UNIX timestamp or date string
|
||||
* @return integer
|
||||
*/
|
||||
public static function offset($remote, $local = NULL, $now = NULL)
|
||||
{
|
||||
if ($local === NULL)
|
||||
{
|
||||
// Use the default timezone
|
||||
$local = date_default_timezone_get();
|
||||
}
|
||||
|
||||
if (is_int($now))
|
||||
{
|
||||
// Convert the timestamp into a string
|
||||
$now = date(DateTime::RFC2822, $now);
|
||||
}
|
||||
|
||||
// Create timezone objects
|
||||
$zone_remote = new DateTimeZone($remote);
|
||||
$zone_local = new DateTimeZone($local);
|
||||
|
||||
// Create date objects from timezones
|
||||
$time_remote = new DateTime($now, $zone_remote);
|
||||
$time_local = new DateTime($now, $zone_local);
|
||||
|
||||
// Find the offset
|
||||
$offset = $zone_remote->getOffset($time_remote) - $zone_local->getOffset($time_local);
|
||||
|
||||
return $offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of seconds in a minute, incrementing by a step. Typically used as
|
||||
* a shortcut for generating a list that can used in a form.
|
||||
*
|
||||
* $seconds = Date::seconds(); // 01, 02, 03, ..., 58, 59, 60
|
||||
*
|
||||
* @param integer amount to increment each step by, 1 to 30
|
||||
* @param integer start value
|
||||
* @param integer end value
|
||||
* @return array A mirrored (foo => foo) array from 1-60.
|
||||
*/
|
||||
public static function seconds($step = 1, $start = 0, $end = 60)
|
||||
{
|
||||
// Always integer
|
||||
$step = (int) $step;
|
||||
|
||||
$seconds = array();
|
||||
|
||||
for ($i = $start; $i < $end; $i += $step)
|
||||
{
|
||||
$seconds[$i] = sprintf('%02d', $i);
|
||||
}
|
||||
|
||||
return $seconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of minutes in an hour, incrementing by a step. Typically used as
|
||||
* a shortcut for generating a list that can be used in a form.
|
||||
*
|
||||
* $minutes = Date::minutes(); // 05, 10, 15, ..., 50, 55, 60
|
||||
*
|
||||
* @uses Date::seconds
|
||||
* @param integer amount to increment each step by, 1 to 30
|
||||
* @return array A mirrored (foo => foo) array from 1-60.
|
||||
*/
|
||||
public static function minutes($step = 5)
|
||||
{
|
||||
// Because there are the same number of minutes as seconds in this set,
|
||||
// we choose to re-use seconds(), rather than creating an entirely new
|
||||
// function. Shhhh, it's cheating! ;) There are several more of these
|
||||
// in the following methods.
|
||||
return Date::seconds($step);
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of hours in a day. Typically used as a shortcut for generating a
|
||||
* list that can be used in a form.
|
||||
*
|
||||
* $hours = Date::hours(); // 01, 02, 03, ..., 10, 11, 12
|
||||
*
|
||||
* @param integer amount to increment each step by
|
||||
* @param boolean use 24-hour time
|
||||
* @param integer the hour to start at
|
||||
* @return array A mirrored (foo => foo) array from start-12 or start-23.
|
||||
*/
|
||||
public static function hours($step = 1, $long = FALSE, $start = NULL)
|
||||
{
|
||||
// Default values
|
||||
$step = (int) $step;
|
||||
$long = (bool) $long;
|
||||
$hours = array();
|
||||
|
||||
// Set the default start if none was specified.
|
||||
if ($start === NULL)
|
||||
{
|
||||
$start = ($long === FALSE) ? 1 : 0;
|
||||
}
|
||||
|
||||
$hours = array();
|
||||
|
||||
// 24-hour time has 24 hours, instead of 12
|
||||
$size = ($long === TRUE) ? 23 : 12;
|
||||
|
||||
for ($i = $start; $i <= $size; $i += $step)
|
||||
{
|
||||
$hours[$i] = (string) $i;
|
||||
}
|
||||
|
||||
return $hours;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns AM or PM, based on a given hour (in 24 hour format).
|
||||
*
|
||||
* $type = Date::ampm(12); // PM
|
||||
* $type = Date::ampm(1); // AM
|
||||
*
|
||||
* @param integer number of the hour
|
||||
* @return string
|
||||
*/
|
||||
public static function ampm($hour)
|
||||
{
|
||||
// Always integer
|
||||
$hour = (int) $hour;
|
||||
|
||||
return ($hour > 11) ? 'PM' : 'AM';
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjusts a non-24-hour number into a 24-hour number.
|
||||
*
|
||||
* $hour = Date::adjust(3, 'pm'); // 15
|
||||
*
|
||||
* @param integer hour to adjust
|
||||
* @param string AM or PM
|
||||
* @return string
|
||||
*/
|
||||
public static function adjust($hour, $ampm)
|
||||
{
|
||||
$hour = (int) $hour;
|
||||
$ampm = strtolower($ampm);
|
||||
|
||||
switch ($ampm)
|
||||
{
|
||||
case 'am':
|
||||
if ($hour == 12)
|
||||
$hour = 0;
|
||||
break;
|
||||
case 'pm':
|
||||
if ($hour < 12)
|
||||
$hour += 12;
|
||||
break;
|
||||
}
|
||||
|
||||
return sprintf('%02d', $hour);
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of days in a given month and year. Typically used as a shortcut
|
||||
* for generating a list that can be used in a form.
|
||||
*
|
||||
* Date::days(4, 2010); // 1, 2, 3, ..., 28, 29, 30
|
||||
*
|
||||
* @param integer number of month
|
||||
* @param integer number of year to check month, defaults to the current year
|
||||
* @return array A mirrored (foo => foo) array of the days.
|
||||
*/
|
||||
public static function days($month, $year = FALSE)
|
||||
{
|
||||
static $months;
|
||||
|
||||
if ($year === FALSE)
|
||||
{
|
||||
// Use the current year by default
|
||||
$year = date('Y');
|
||||
}
|
||||
|
||||
// Always integers
|
||||
$month = (int) $month;
|
||||
$year = (int) $year;
|
||||
|
||||
// We use caching for months, because time functions are used
|
||||
if (empty($months[$year][$month]))
|
||||
{
|
||||
$months[$year][$month] = array();
|
||||
|
||||
// Use date to find the number of days in the given month
|
||||
$total = date('t', mktime(1, 0, 0, $month, 1, $year)) + 1;
|
||||
|
||||
for ($i = 1; $i < $total; $i++)
|
||||
{
|
||||
$months[$year][$month][$i] = (string) $i;
|
||||
}
|
||||
}
|
||||
|
||||
return $months[$year][$month];
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of months in a year. Typically used as a shortcut for generating
|
||||
* a list that can be used in a form.
|
||||
*
|
||||
* Date::months(); // 01, 02, 03, ..., 10, 11, 12
|
||||
*
|
||||
* @uses Date::hours
|
||||
* @return array A mirrored (foo => foo) array from 1-12.
|
||||
*/
|
||||
public static function months()
|
||||
{
|
||||
return Date::hours();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of years between a starting and ending year. By default,
|
||||
* the the current year - 5 and current year + 5 will be used. Typically used
|
||||
* as a shortcut for generating a list that can be used in a form.
|
||||
*
|
||||
* $years = Date::years(2000, 2010); // 2000, 2001, ..., 2009, 2010
|
||||
*
|
||||
* @param integer starting year (default is current year - 5)
|
||||
* @param integer ending year (default is current year + 5)
|
||||
* @return array
|
||||
*/
|
||||
public static function years($start = FALSE, $end = FALSE)
|
||||
{
|
||||
// Default values
|
||||
$start = ($start === FALSE) ? date('Y') - 5 : (int) $start;
|
||||
$end = ($end === FALSE) ? date('Y') + 5 : (int) $end;
|
||||
|
||||
$years = array();
|
||||
|
||||
for ($i = $start; $i <= $end; $i++)
|
||||
{
|
||||
$years[$i] = (string) $i;
|
||||
}
|
||||
|
||||
return $years;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns time difference between two timestamps, in human readable format.
|
||||
* If the second timestamp is not given, the current time will be used.
|
||||
* Also consider using [Date::fuzzy_span] when displaying a span.
|
||||
*
|
||||
* $span = Date::span(60, 182, 'minutes,seconds'); // array('minutes' => 2, 'seconds' => 2)
|
||||
* $span = Date::span(60, 182, 'minutes'); // 2
|
||||
*
|
||||
* @param integer timestamp to find the span of
|
||||
* @param integer timestamp to use as the baseline
|
||||
* @param string formatting string
|
||||
* @return string when only a single output is requested
|
||||
* @return array associative list of all outputs requested
|
||||
*/
|
||||
public static function span($remote, $local = NULL, $output = 'years,months,weeks,days,hours,minutes,seconds')
|
||||
{
|
||||
// Normalize output
|
||||
$output = trim(strtolower((string) $output));
|
||||
|
||||
if ( ! $output)
|
||||
{
|
||||
// Invalid output
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Array with the output formats
|
||||
$output = preg_split('/[^a-z]+/', $output);
|
||||
|
||||
// Convert the list of outputs to an associative array
|
||||
$output = array_combine($output, array_fill(0, count($output), 0));
|
||||
|
||||
// Make the output values into keys
|
||||
extract(array_flip($output), EXTR_SKIP);
|
||||
|
||||
if ($local === NULL)
|
||||
{
|
||||
// Calculate the span from the current time
|
||||
$local = time();
|
||||
}
|
||||
|
||||
// Calculate timespan (seconds)
|
||||
$timespan = abs($remote - $local);
|
||||
|
||||
if (isset($output['years']))
|
||||
{
|
||||
$timespan -= Date::YEAR * ($output['years'] = (int) floor($timespan / Date::YEAR));
|
||||
}
|
||||
|
||||
if (isset($output['months']))
|
||||
{
|
||||
$timespan -= Date::MONTH * ($output['months'] = (int) floor($timespan / Date::MONTH));
|
||||
}
|
||||
|
||||
if (isset($output['weeks']))
|
||||
{
|
||||
$timespan -= Date::WEEK * ($output['weeks'] = (int) floor($timespan / Date::WEEK));
|
||||
}
|
||||
|
||||
if (isset($output['days']))
|
||||
{
|
||||
$timespan -= Date::DAY * ($output['days'] = (int) floor($timespan / Date::DAY));
|
||||
}
|
||||
|
||||
if (isset($output['hours']))
|
||||
{
|
||||
$timespan -= Date::HOUR * ($output['hours'] = (int) floor($timespan / Date::HOUR));
|
||||
}
|
||||
|
||||
if (isset($output['minutes']))
|
||||
{
|
||||
$timespan -= Date::MINUTE * ($output['minutes'] = (int) floor($timespan / Date::MINUTE));
|
||||
}
|
||||
|
||||
// Seconds ago, 1
|
||||
if (isset($output['seconds']))
|
||||
{
|
||||
$output['seconds'] = $timespan;
|
||||
}
|
||||
|
||||
if (count($output) === 1)
|
||||
{
|
||||
// Only a single output was requested, return it
|
||||
return array_pop($output);
|
||||
}
|
||||
|
||||
// Return array
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the difference between a time and now in a "fuzzy" way.
|
||||
* Note that unlike [Date::span], the "local" timestamp will always be the
|
||||
* current time. Displaying a fuzzy time instead of a date is usually
|
||||
* faster to read and understand.
|
||||
*
|
||||
* $span = Date::fuzzy_span(time() - 10); // "moments ago"
|
||||
* $span = Date::fuzzy_span(time() + 20); // "in moments"
|
||||
*
|
||||
* @param integer "remote" timestamp
|
||||
* @return string
|
||||
*/
|
||||
public static function fuzzy_span($timestamp)
|
||||
{
|
||||
// Determine the difference in seconds
|
||||
$offset = abs(time() - $timestamp);
|
||||
|
||||
if ($offset <= Date::MINUTE)
|
||||
{
|
||||
$span = 'moments';
|
||||
}
|
||||
elseif ($offset < (Date::MINUTE * 20))
|
||||
{
|
||||
$span = 'a few minutes';
|
||||
}
|
||||
elseif ($offset < Date::HOUR)
|
||||
{
|
||||
$span = 'less than an hour';
|
||||
}
|
||||
elseif ($offset < (Date::HOUR * 4))
|
||||
{
|
||||
$span = 'a couple of hours';
|
||||
}
|
||||
elseif ($offset < Date::DAY)
|
||||
{
|
||||
$span = 'less than a day';
|
||||
}
|
||||
elseif ($offset < (Date::DAY * 2))
|
||||
{
|
||||
$span = 'about a day';
|
||||
}
|
||||
elseif ($offset < (Date::DAY * 4))
|
||||
{
|
||||
$span = 'a couple of days';
|
||||
}
|
||||
elseif ($offset < Date::WEEK)
|
||||
{
|
||||
$span = 'less than a week';
|
||||
}
|
||||
elseif ($offset < (Date::WEEK * 2))
|
||||
{
|
||||
$span = 'about a week';
|
||||
}
|
||||
elseif ($offset < Date::MONTH)
|
||||
{
|
||||
$span = 'less than a month';
|
||||
}
|
||||
elseif ($offset < (Date::MONTH * 2))
|
||||
{
|
||||
$span = 'about a month';
|
||||
}
|
||||
elseif ($offset < (Date::MONTH * 4))
|
||||
{
|
||||
$span = 'a couple of months';
|
||||
}
|
||||
elseif ($offset < Date::YEAR)
|
||||
{
|
||||
$span = 'less than a year';
|
||||
}
|
||||
elseif ($offset < (Date::YEAR * 2))
|
||||
{
|
||||
$span = 'about a year';
|
||||
}
|
||||
elseif ($offset < (Date::YEAR * 4))
|
||||
{
|
||||
$span = 'a couple of years';
|
||||
}
|
||||
elseif ($offset < (Date::YEAR * 8))
|
||||
{
|
||||
$span = 'a few years';
|
||||
}
|
||||
elseif ($offset < (Date::YEAR * 12))
|
||||
{
|
||||
$span = 'about a decade';
|
||||
}
|
||||
elseif ($offset < (Date::YEAR * 24))
|
||||
{
|
||||
$span = 'a couple of decades';
|
||||
}
|
||||
elseif ($offset < (Date::YEAR * 64))
|
||||
{
|
||||
$span = 'several decades';
|
||||
}
|
||||
else
|
||||
{
|
||||
$span = 'a long time';
|
||||
}
|
||||
|
||||
if ($timestamp <= time())
|
||||
{
|
||||
// This is in the past
|
||||
return $span.' ago';
|
||||
}
|
||||
else
|
||||
{
|
||||
// This in the future
|
||||
return 'in '.$span;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a UNIX timestamp to DOS format. There are very few cases where
|
||||
* this is needed, but some binary formats use it (eg: zip files.)
|
||||
* Converting the other direction is done using {@link Date::dos2unix}.
|
||||
*
|
||||
* $dos = Date::unix2dos($unix);
|
||||
*
|
||||
* @param integer UNIX timestamp
|
||||
* @return integer
|
||||
*/
|
||||
public static function unix2dos($timestamp = FALSE)
|
||||
{
|
||||
$timestamp = ($timestamp === FALSE) ? getdate() : getdate($timestamp);
|
||||
|
||||
if ($timestamp['year'] < 1980)
|
||||
{
|
||||
return (1 << 21 | 1 << 16);
|
||||
}
|
||||
|
||||
$timestamp['year'] -= 1980;
|
||||
|
||||
// What voodoo is this? I have no idea... Geert can explain it though,
|
||||
// and that's good enough for me.
|
||||
return ($timestamp['year'] << 25 | $timestamp['mon'] << 21 |
|
||||
$timestamp['mday'] << 16 | $timestamp['hours'] << 11 |
|
||||
$timestamp['minutes'] << 5 | $timestamp['seconds'] >> 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a DOS timestamp to UNIX format.There are very few cases where
|
||||
* this is needed, but some binary formats use it (eg: zip files.)
|
||||
* Converting the other direction is done using {@link Date::unix2dos}.
|
||||
*
|
||||
* $unix = Date::dos2unix($dos);
|
||||
*
|
||||
* @param integer DOS timestamp
|
||||
* @return integer
|
||||
*/
|
||||
public static function dos2unix($timestamp = FALSE)
|
||||
{
|
||||
$sec = 2 * ($timestamp & 0x1f);
|
||||
$min = ($timestamp >> 5) & 0x3f;
|
||||
$hrs = ($timestamp >> 11) & 0x1f;
|
||||
$day = ($timestamp >> 16) & 0x1f;
|
||||
$mon = ($timestamp >> 21) & 0x0f;
|
||||
$year = ($timestamp >> 25) & 0x7f;
|
||||
|
||||
return mktime($hrs, $min, $sec, $mon, $day, $year + 1980);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a date/time string with the specified timestamp format
|
||||
*
|
||||
* $time = Date::formatted_time('5 minutes ago');
|
||||
*
|
||||
* @see http://php.net/manual/en/datetime.construct.php
|
||||
* @param string datetime_str datetime string
|
||||
* @param string timestamp_format timestamp format
|
||||
* @return string
|
||||
*/
|
||||
public static function formatted_time($datetime_str = 'now', $timestamp_format = NULL, $timezone = NULL)
|
||||
{
|
||||
$timestamp_format = $timestamp_format == NULL ? Date::$timestamp_format : $timestamp_format;
|
||||
$timezone = $timezone === NULL ? Date::$timezone : $timezone;
|
||||
|
||||
$time = new DateTime($datetime_str, new DateTimeZone(
|
||||
$timezone ? $timezone : date_default_timezone_get()
|
||||
));
|
||||
|
||||
return $time->format($timestamp_format);
|
||||
}
|
||||
|
||||
} // End date
|
211
includes/kohana/system/classes/kohana/encrypt.php
Normal file
211
includes/kohana/system/classes/kohana/encrypt.php
Normal file
@@ -0,0 +1,211 @@
|
||||
<?php defined('SYSPATH') or die('No direct access allowed.');
|
||||
/**
|
||||
* The Encrypt library provides two-way encryption of text and binary strings
|
||||
* using the [Mcrypt](http://php.net/mcrypt) extension, which consists of three
|
||||
* parts: the key, the cipher, and the mode.
|
||||
*
|
||||
* The Key
|
||||
* : A secret passphrase that is used for encoding and decoding
|
||||
*
|
||||
* The Cipher
|
||||
* : A [cipher](http://php.net/mcrypt.ciphers) determines how the encryption
|
||||
* is mathematically calculated. By default, the "rijndael-128" cipher
|
||||
* is used. This is commonly known as "AES-128" and is an industry standard.
|
||||
*
|
||||
* The Mode
|
||||
* : The [mode](http://php.net/mcrypt.constants) determines how the encrypted
|
||||
* data is written in binary form. By default, the "nofb" mode is used,
|
||||
* which produces short output with high entropy.
|
||||
*
|
||||
* @package Kohana
|
||||
* @category Security
|
||||
* @author Kohana Team
|
||||
* @copyright (c) 2007-2010 Kohana Team
|
||||
* @license http://kohanaphp.com/license
|
||||
*/
|
||||
class Kohana_Encrypt {
|
||||
|
||||
/**
|
||||
* @var string default instance name
|
||||
*/
|
||||
public static $default = 'default';
|
||||
|
||||
/**
|
||||
* @var array Encrypt class instances
|
||||
*/
|
||||
public static $instances = array();
|
||||
|
||||
// OS-dependent RAND type to use
|
||||
protected static $_rand;
|
||||
|
||||
/**
|
||||
* Returns a singleton instance of Encrypt. An encryption key must be
|
||||
* provided in your "encrypt" configuration file.
|
||||
*
|
||||
* $encrypt = Encrypt::instance();
|
||||
*
|
||||
* @param string configuration group name
|
||||
* @return object
|
||||
*/
|
||||
public static function instance($name = NULL)
|
||||
{
|
||||
if ($name === NULL)
|
||||
{
|
||||
// Use the default instance name
|
||||
$name = Encrypt::$default;
|
||||
}
|
||||
|
||||
if ( ! isset(Encrypt::$instances[$name]))
|
||||
{
|
||||
// Load the configuration data
|
||||
$config = Kohana::config('encrypt')->$name;
|
||||
|
||||
if ( ! isset($config['key']))
|
||||
{
|
||||
// No default encryption key is provided!
|
||||
throw new Kohana_Exception('No encryption key is defined in the encryption configuration group: :group',
|
||||
array(':group' => $name));
|
||||
}
|
||||
|
||||
if ( ! isset($config['mode']))
|
||||
{
|
||||
// Add the default mode
|
||||
$config['mode'] = MCRYPT_MODE_NOFB;
|
||||
}
|
||||
|
||||
if ( ! isset($config['cipher']))
|
||||
{
|
||||
// Add the default cipher
|
||||
$config['cipher'] = MCRYPT_RIJNDAEL_128;
|
||||
}
|
||||
|
||||
// Create a new instance
|
||||
Encrypt::$instances[$name] = new Encrypt($config['key'], $config['mode'], $config['cipher']);
|
||||
}
|
||||
|
||||
return Encrypt::$instances[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new mcrypt wrapper.
|
||||
*
|
||||
* @param string encryption key
|
||||
* @param string mcrypt mode
|
||||
* @param string mcrypt cipher
|
||||
*/
|
||||
public function __construct($key, $mode, $cipher)
|
||||
{
|
||||
// Find the max length of the key, based on cipher and mode
|
||||
$size = mcrypt_get_key_size($cipher, $mode);
|
||||
|
||||
if (isset($key[$size]))
|
||||
{
|
||||
// Shorten the key to the maximum size
|
||||
$key = substr($key, 0, $size);
|
||||
}
|
||||
|
||||
// Store the key, mode, and cipher
|
||||
$this->_key = $key;
|
||||
$this->_mode = $mode;
|
||||
$this->_cipher = $cipher;
|
||||
|
||||
// Store the IV size
|
||||
$this->_iv_size = mcrypt_get_iv_size($this->_cipher, $this->_mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypts a string and returns an encrypted string that can be decoded.
|
||||
*
|
||||
* $data = $encrypt->encode($data);
|
||||
*
|
||||
* The encrypted binary data is encoded using [base64](http://php.net/base64_encode)
|
||||
* to convert it to a string. This string can be stored in a database,
|
||||
* displayed, and passed using most other means without corruption.
|
||||
*
|
||||
* @param string data to be encrypted
|
||||
* @return string
|
||||
*/
|
||||
public function encode($data)
|
||||
{
|
||||
// Set the rand type if it has not already been set
|
||||
if (Encrypt::$_rand === NULL)
|
||||
{
|
||||
if (Kohana::$is_windows)
|
||||
{
|
||||
// Windows only supports the system random number generator
|
||||
Encrypt::$_rand = MCRYPT_RAND;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (defined('MCRYPT_DEV_URANDOM'))
|
||||
{
|
||||
// Use /dev/urandom
|
||||
Encrypt::$_rand = MCRYPT_DEV_URANDOM;
|
||||
}
|
||||
elseif (defined('MCRYPT_DEV_RANDOM'))
|
||||
{
|
||||
// Use /dev/random
|
||||
Encrypt::$_rand = MCRYPT_DEV_RANDOM;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use the system random number generator
|
||||
Encrypt::$_rand = MCRYPT_RAND;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Encrypt::$_rand === MCRYPT_RAND)
|
||||
{
|
||||
// The system random number generator must always be seeded each
|
||||
// time it is used, or it will not produce true random results
|
||||
mt_srand();
|
||||
}
|
||||
|
||||
// Create a random initialization vector of the proper size for the current cipher
|
||||
$iv = mcrypt_create_iv($this->_iv_size, Encrypt::$_rand);
|
||||
|
||||
// Encrypt the data using the configured options and generated iv
|
||||
$data = mcrypt_encrypt($this->_cipher, $this->_key, $data, $this->_mode, $iv);
|
||||
|
||||
// Use base64 encoding to convert to a string
|
||||
return base64_encode($iv.$data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypts an encoded string back to its original value.
|
||||
*
|
||||
* $data = $encrypt->decode($data);
|
||||
*
|
||||
* @param string encoded string to be decrypted
|
||||
* @return FALSE if decryption fails
|
||||
* @return string
|
||||
*/
|
||||
public function decode($data)
|
||||
{
|
||||
// Convert the data back to binary
|
||||
$data = base64_decode($data, TRUE);
|
||||
|
||||
if ( ! $data)
|
||||
{
|
||||
// Invalid base64 data
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Extract the initialization vector from the data
|
||||
$iv = substr($data, 0, $this->_iv_size);
|
||||
|
||||
if ($this->_iv_size !== strlen($iv))
|
||||
{
|
||||
// The iv is not the expected size
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Remove the iv from the data
|
||||
$data = substr($data, $this->_iv_size);
|
||||
|
||||
// Return the decrypted data, trimming the \0 padding bytes from the end of the data
|
||||
return rtrim(mcrypt_decrypt($this->_cipher, $this->_key, $data, $this->_mode, $iv), "\0");
|
||||
}
|
||||
|
||||
} // End Encrypt
|
46
includes/kohana/system/classes/kohana/exception.php
Normal file
46
includes/kohana/system/classes/kohana/exception.php
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php defined('SYSPATH') or die('No direct access');
|
||||
/**
|
||||
* Kohana exception class. Translates exceptions using the [I18n] class.
|
||||
*
|
||||
* @package Kohana
|
||||
* @category Exceptions
|
||||
* @author Kohana Team
|
||||
* @copyright (c) 2008-2009 Kohana Team
|
||||
* @license http://kohanaphp.com/license
|
||||
*/
|
||||
class Kohana_Exception extends Exception {
|
||||
|
||||
/**
|
||||
* Creates a new translated exception.
|
||||
*
|
||||
* throw new Kohana_Exception('Something went terrible wrong, :user',
|
||||
* array(':user' => $user));
|
||||
*
|
||||
* @param string error message
|
||||
* @param array translation variables
|
||||
* @param integer the exception code
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($message, array $variables = NULL, $code = 0)
|
||||
{
|
||||
// Set the message
|
||||
$message = __($message, $variables);
|
||||
|
||||
// Pass the message to the parent
|
||||
parent::__construct($message, $code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic object-to-string method.
|
||||
*
|
||||
* echo $exception;
|
||||
*
|
||||
* @uses Kohana::exception_text
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return Kohana::exception_text($this);
|
||||
}
|
||||
|
||||
} // End Kohana_Exception
|
176
includes/kohana/system/classes/kohana/feed.php
Normal file
176
includes/kohana/system/classes/kohana/feed.php
Normal file
@@ -0,0 +1,176 @@
|
||||
<?php defined('SYSPATH') or die('No direct access allowed.');
|
||||
/**
|
||||
* RSS and Atom feed helper.
|
||||
*
|
||||
* @package Kohana
|
||||
* @category Helpers
|
||||
* @author Kohana Team
|
||||
* @copyright (c) 2007-2009 Kohana Team
|
||||
* @license http://kohanaphp.com/license
|
||||
*/
|
||||
class Kohana_Feed {
|
||||
|
||||
/**
|
||||
* Parses a remote feed into an array.
|
||||
*
|
||||
* @param string remote feed URL
|
||||
* @param integer item limit to fetch
|
||||
* @return array
|
||||
*/
|
||||
public static function parse($feed, $limit = 0)
|
||||
{
|
||||
// Check if SimpleXML is installed
|
||||
if( ! function_exists('simplexml_load_file'))
|
||||
throw new Kohana_Exception('SimpleXML must be installed!');
|
||||
|
||||
// Make limit an integer
|
||||
$limit = (int) $limit;
|
||||
|
||||
// Disable error reporting while opening the feed
|
||||
$ER = error_reporting(0);
|
||||
|
||||
// Allow loading by filename or raw XML string
|
||||
$load = (is_file($feed) OR validate::url($feed)) ? 'simplexml_load_file' : 'simplexml_load_string';
|
||||
|
||||
// Load the feed
|
||||
$feed = $load($feed, 'SimpleXMLElement', LIBXML_NOCDATA);
|
||||
|
||||
// Restore error reporting
|
||||
error_reporting($ER);
|
||||
|
||||
// Feed could not be loaded
|
||||
if ($feed === FALSE)
|
||||
return array();
|
||||
|
||||
$namespaces = $feed->getNamespaces(true);
|
||||
|
||||
// Detect the feed type. RSS 1.0/2.0 and Atom 1.0 are supported.
|
||||
$feed = isset($feed->channel) ? $feed->xpath('//item') : $feed->entry;
|
||||
|
||||
$i = 0;
|
||||
$items = array();
|
||||
|
||||
foreach ($feed as $item)
|
||||
{
|
||||
if ($limit > 0 AND $i++ === $limit)
|
||||
break;
|
||||
$item_fields = (array) $item;
|
||||
|
||||
// get namespaced tags
|
||||
foreach ($namespaces as $ns)
|
||||
{
|
||||
$item_fields += (array) $item->children($ns);
|
||||
}
|
||||
$items[] = $item_fields;
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a feed from the given parameters.
|
||||
*
|
||||
* @param array feed information
|
||||
* @param array items to add to the feed
|
||||
* @param string define which format to use (only rss2 is supported)
|
||||
* @param string define which encoding to use
|
||||
* @return string
|
||||
*/
|
||||
public static function create($info, $items, $format = 'rss2', $encoding = 'UTF-8')
|
||||
{
|
||||
$info += array('title' => 'Generated Feed', 'link' => '', 'generator' => 'KohanaPHP');
|
||||
|
||||
$feed = '<?xml version="1.0" encoding="'.$encoding.'"?><rss version="2.0"><channel></channel></rss>';
|
||||
$feed = simplexml_load_string($feed);
|
||||
|
||||
foreach ($info as $name => $value)
|
||||
{
|
||||
if ($name === 'image')
|
||||
{
|
||||
// Create an image element
|
||||
$image = $feed->channel->addChild('image');
|
||||
|
||||
if ( ! isset($value['link'], $value['url'], $value['title']))
|
||||
{
|
||||
throw new Kohana_Exception('Feed images require a link, url, and title');
|
||||
}
|
||||
|
||||
if (strpos($value['link'], '://') === FALSE)
|
||||
{
|
||||
// Convert URIs to URLs
|
||||
$value['link'] = URL::site($value['link'], 'http');
|
||||
}
|
||||
|
||||
if (strpos($value['url'], '://') === FALSE)
|
||||
{
|
||||
// Convert URIs to URLs
|
||||
$value['url'] = URL::site($value['url'], 'http');
|
||||
}
|
||||
|
||||
// Create the image elements
|
||||
$image->addChild('link', $value['link']);
|
||||
$image->addChild('url', $value['url']);
|
||||
$image->addChild('title', $value['title']);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (($name === 'pubDate' OR $name === 'lastBuildDate') AND (is_int($value) OR ctype_digit($value)))
|
||||
{
|
||||
// Convert timestamps to RFC 822 formatted dates
|
||||
$value = date('r', $value);
|
||||
}
|
||||
elseif (($name === 'link' OR $name === 'docs') AND strpos($value, '://') === FALSE)
|
||||
{
|
||||
// Convert URIs to URLs
|
||||
$value = URL::site($value, 'http');
|
||||
}
|
||||
|
||||
// Add the info to the channel
|
||||
$feed->channel->addChild($name, $value);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($items as $item)
|
||||
{
|
||||
// Add the item to the channel
|
||||
$row = $feed->channel->addChild('item');
|
||||
|
||||
foreach ($item as $name => $value)
|
||||
{
|
||||
if ($name === 'pubDate' AND (is_int($value) OR ctype_digit($value)))
|
||||
{
|
||||
// Convert timestamps to RFC 822 formatted dates
|
||||
$value = date('r', $value);
|
||||
}
|
||||
elseif (($name === 'link' OR $name === 'guid') AND strpos($value, '://') === FALSE)
|
||||
{
|
||||
// Convert URIs to URLs
|
||||
$value = URL::site($value, 'http');
|
||||
}
|
||||
|
||||
// Add the info to the row
|
||||
$row->addChild($name, $value);
|
||||
}
|
||||
}
|
||||
|
||||
if (function_exists('dom_import_simplexml'))
|
||||
{
|
||||
// Convert the feed object to a DOM object
|
||||
$feed = dom_import_simplexml($feed)->ownerDocument;
|
||||
|
||||
// DOM generates more readable XML
|
||||
$feed->formatOutput = TRUE;
|
||||
|
||||
// Export the document as XML
|
||||
$feed = $feed->saveXML();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Export the document as XML
|
||||
$feed = $feed->asXML();
|
||||
}
|
||||
|
||||
return $feed;
|
||||
}
|
||||
|
||||
} // End Feed
|
179
includes/kohana/system/classes/kohana/file.php
Normal file
179
includes/kohana/system/classes/kohana/file.php
Normal file
@@ -0,0 +1,179 @@
|
||||
<?php defined('SYSPATH') or die('No direct access allowed.');
|
||||
/**
|
||||
* File helper class.
|
||||
*
|
||||
* @package Kohana
|
||||
* @category Helpers
|
||||
* @author Kohana Team
|
||||
* @copyright (c) 2007-2009 Kohana Team
|
||||
* @license http://kohanaphp.com/license
|
||||
*/
|
||||
class Kohana_File {
|
||||
|
||||
/**
|
||||
* Attempt to get the mime type from a file. This method is horribly
|
||||
* unreliable, due to PHP being horribly unreliable when it comes to
|
||||
* determining the mime type of a file.
|
||||
*
|
||||
* $mime = File::mime($file);
|
||||
*
|
||||
* @param string file name or path
|
||||
* @return string mime type on success
|
||||
* @return FALSE on failure
|
||||
*/
|
||||
public static function mime($filename)
|
||||
{
|
||||
// Get the complete path to the file
|
||||
$filename = realpath($filename);
|
||||
|
||||
// Get the extension from the filename
|
||||
$extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
|
||||
|
||||
if (preg_match('/^(?:jpe?g|png|[gt]if|bmp|swf)$/', $extension))
|
||||
{
|
||||
// Use getimagesize() to find the mime type on images
|
||||
$file = getimagesize($filename);
|
||||
|
||||
if (isset($file['mime']))
|
||||
return $file['mime'];
|
||||
}
|
||||
|
||||
if (class_exists('finfo', FALSE))
|
||||
{
|
||||
if ($info = new finfo(FILEINFO_MIME_TYPE))
|
||||
{
|
||||
return $info->file($filename);
|
||||
}
|
||||
}
|
||||
|
||||
if (ini_get('mime_magic.magicfile') AND function_exists('mime_content_type'))
|
||||
{
|
||||
// The mime_content_type function is only useful with a magic file
|
||||
return mime_content_type($filename);
|
||||
}
|
||||
|
||||
if ( ! empty($extension))
|
||||
{
|
||||
return File::mime_by_ext($extension);
|
||||
}
|
||||
|
||||
// Unable to find the mime-type
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the mime type of an extension.
|
||||
*
|
||||
* $mime = File::mime_by_ext('png'); // "image/png"
|
||||
*
|
||||
* @param string extension: php, pdf, txt, etc
|
||||
* @return string mime type on success
|
||||
* @return FALSE on failure
|
||||
*/
|
||||
public static function mime_by_ext($extension)
|
||||
{
|
||||
// Load all of the mime types
|
||||
$mimes = Kohana::config('mimes');
|
||||
|
||||
return isset($mimes[$extension]) ? $mimes[$extension][0] : FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Split a file into pieces matching a specific size. Used when you need to
|
||||
* split large files into smaller pieces for easy transmission.
|
||||
*
|
||||
* $count = File::split($file);
|
||||
*
|
||||
* @param string file to be split
|
||||
* @param string directory to output to, defaults to the same directory as the file
|
||||
* @param integer size, in MB, for each piece to be
|
||||
* @return integer The number of pieces that were created
|
||||
*/
|
||||
public static function split($filename, $piece_size = 10)
|
||||
{
|
||||
// Open the input file
|
||||
$file = fopen($filename, 'rb');
|
||||
|
||||
// Change the piece size to bytes
|
||||
$piece_size = floor($piece_size * 1024 * 1024);
|
||||
|
||||
// Write files in 8k blocks
|
||||
$block_size = 1024 * 8;
|
||||
|
||||
// Total number of peices
|
||||
$peices = 0;
|
||||
|
||||
while ( ! feof($file))
|
||||
{
|
||||
// Create another piece
|
||||
$peices += 1;
|
||||
|
||||
// Create a new file piece
|
||||
$piece = str_pad($peices, 3, '0', STR_PAD_LEFT);
|
||||
$piece = fopen($filename.'.'.$piece, 'wb+');
|
||||
|
||||
// Number of bytes read
|
||||
$read = 0;
|
||||
|
||||
do
|
||||
{
|
||||
// Transfer the data in blocks
|
||||
fwrite($piece, fread($file, $block_size));
|
||||
|
||||
// Another block has been read
|
||||
$read += $block_size;
|
||||
}
|
||||
while ($read < $piece_size);
|
||||
|
||||
// Close the piece
|
||||
fclose($piece);
|
||||
}
|
||||
|
||||
// Close the file
|
||||
fclose($file);
|
||||
|
||||
return $peices;
|
||||
}
|
||||
|
||||
/**
|
||||
* Join a split file into a whole file. Does the reverse of [File::split].
|
||||
*
|
||||
* $count = File::join($file);
|
||||
*
|
||||
* @param string split filename, without .000 extension
|
||||
* @param string output filename, if different then an the filename
|
||||
* @return integer The number of pieces that were joined.
|
||||
*/
|
||||
public static function join($filename)
|
||||
{
|
||||
// Open the file
|
||||
$file = fopen($filename, 'wb+');
|
||||
|
||||
// Read files in 8k blocks
|
||||
$block_size = 1024 * 8;
|
||||
|
||||
// Total number of peices
|
||||
$pieces = 0;
|
||||
|
||||
while (is_file($piece = $filename.'.'.str_pad($pieces + 1, 3, '0', STR_PAD_LEFT)))
|
||||
{
|
||||
// Read another piece
|
||||
$pieces += 1;
|
||||
|
||||
// Open the piece for reading
|
||||
$piece = fopen($piece, 'rb');
|
||||
|
||||
while ( ! feof($piece))
|
||||
{
|
||||
// Transfer the data in blocks
|
||||
fwrite($file, fread($piece, $block_size));
|
||||
}
|
||||
|
||||
// Close the peice
|
||||
fclose($piece);
|
||||
}
|
||||
|
||||
return $pieces;
|
||||
}
|
||||
|
||||
} // End file
|
434
includes/kohana/system/classes/kohana/form.php
Normal file
434
includes/kohana/system/classes/kohana/form.php
Normal file
@@ -0,0 +1,434 @@
|
||||
<?php defined('SYSPATH') or die('No direct access allowed.');
|
||||
/**
|
||||
* Form helper class. Unless otherwise noted, all generated HTML will be made
|
||||
* safe using the [HTML::chars] method. This prevents against simple XSS
|
||||
* attacks that could otherwise be trigged by inserting HTML characters into
|
||||
* form fields.
|
||||
*
|
||||
* @package Kohana
|
||||
* @category Helpers
|
||||
* @author Kohana Team
|
||||
* @copyright (c) 2007-2008 Kohana Team
|
||||
* @license http://kohanaphp.com/license
|
||||
*/
|
||||
class Kohana_Form {
|
||||
|
||||
/**
|
||||
* Generates an opening HTML form tag.
|
||||
*
|
||||
* // Form will submit back to the current page using POST
|
||||
* echo Form::open();
|
||||
*
|
||||
* // Form will submit to 'search' using GET
|
||||
* echo Form::open('search', array('method' => 'get'));
|
||||
*
|
||||
* // When "file" inputs are present, you must include the "enctype"
|
||||
* echo Form::open(NULL, array('enctype' => 'multipart/form-data'));
|
||||
*
|
||||
* @param string form action, defaults to the current request URI
|
||||
* @param array html attributes
|
||||
* @return string
|
||||
* @uses Request::instance
|
||||
* @uses URL::site
|
||||
* @uses HTML::attributes
|
||||
*/
|
||||
public static function open($action = NULL, array $attributes = NULL)
|
||||
{
|
||||
if ($action === NULL)
|
||||
{
|
||||
// Use the current URI
|
||||
$action = Request::current()->uri;
|
||||
}
|
||||
|
||||
if ($action === '')
|
||||
{
|
||||
// Use only the base URI
|
||||
$action = Kohana::$base_url;
|
||||
}
|
||||
elseif (strpos($action, '://') === FALSE)
|
||||
{
|
||||
// Make the URI absolute
|
||||
$action = URL::site($action);
|
||||
}
|
||||
|
||||
// Add the form action to the attributes
|
||||
$attributes['action'] = $action;
|
||||
|
||||
// Only accept the default character set
|
||||
$attributes['accept-charset'] = Kohana::$charset;
|
||||
|
||||
if ( ! isset($attributes['method']))
|
||||
{
|
||||
// Use POST method
|
||||
$attributes['method'] = 'post';
|
||||
}
|
||||
|
||||
return '<form'.HTML::attributes($attributes).'>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the closing form tag.
|
||||
*
|
||||
* echo Form::close();
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function close()
|
||||
{
|
||||
return '</form>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a form input. If no type is specified, a "text" type input will
|
||||
* be returned.
|
||||
*
|
||||
* echo Form::input('username', $username);
|
||||
*
|
||||
* @param string input name
|
||||
* @param string input value
|
||||
* @param array html attributes
|
||||
* @return string
|
||||
* @uses HTML::attributes
|
||||
*/
|
||||
public static function input($name, $value = NULL, array $attributes = NULL)
|
||||
{
|
||||
// Set the input name
|
||||
$attributes['name'] = $name;
|
||||
|
||||
// Set the input value
|
||||
$attributes['value'] = $value;
|
||||
|
||||
if ( ! isset($attributes['type']))
|
||||
{
|
||||
// Default type is text
|
||||
$attributes['type'] = 'text';
|
||||
}
|
||||
|
||||
return '<input'.HTML::attributes($attributes).' />';
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a hidden form input.
|
||||
*
|
||||
* echo Form::hidden('csrf', $token);
|
||||
*
|
||||
* @param string input name
|
||||
* @param string input value
|
||||
* @param array html attributes
|
||||
* @return string
|
||||
* @uses Form::input
|
||||
*/
|
||||
public static function hidden($name, $value = NULL, array $attributes = NULL)
|
||||
{
|
||||
$attributes['type'] = 'hidden';
|
||||
|
||||
return Form::input($name, $value, $attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a password form input.
|
||||
*
|
||||
* echo Form::password('password');
|
||||
*
|
||||
* @param string input name
|
||||
* @param string input value
|
||||
* @param array html attributes
|
||||
* @return string
|
||||
* @uses Form::input
|
||||
*/
|
||||
public static function password($name, $value = NULL, array $attributes = NULL)
|
||||
{
|
||||
$attributes['type'] = 'password';
|
||||
|
||||
return Form::input($name, $value, $attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a file upload form input. No input value can be specified.
|
||||
*
|
||||
* echo Form::file('image');
|
||||
*
|
||||
* @param string input name
|
||||
* @param array html attributes
|
||||
* @return string
|
||||
* @uses Form::input
|
||||
*/
|
||||
public static function file($name, array $attributes = NULL)
|
||||
{
|
||||
$attributes['type'] = 'file';
|
||||
|
||||
return Form::input($name, NULL, $attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a checkbox form input.
|
||||
*
|
||||
* echo Form::checkbox('remember_me', 1, (bool) $remember);
|
||||
*
|
||||
* @param string input name
|
||||
* @param string input value
|
||||
* @param boolean checked status
|
||||
* @param array html attributes
|
||||
* @return string
|
||||
* @uses Form::input
|
||||
*/
|
||||
public static function checkbox($name, $value = NULL, $checked = FALSE, array $attributes = NULL)
|
||||
{
|
||||
$attributes['type'] = 'checkbox';
|
||||
|
||||
if ($checked === TRUE)
|
||||
{
|
||||
// Make the checkbox active
|
||||
$attributes['checked'] = 'checked';
|
||||
}
|
||||
|
||||
return Form::input($name, $value, $attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a radio form input.
|
||||
*
|
||||
* echo Form::radio('like_cats', 1, $cats);
|
||||
* echo Form::radio('like_cats', 0, ! $cats);
|
||||
*
|
||||
* @param string input name
|
||||
* @param string input value
|
||||
* @param boolean checked status
|
||||
* @param array html attributes
|
||||
* @return string
|
||||
* @uses Form::input
|
||||
*/
|
||||
public static function radio($name, $value = NULL, $checked = FALSE, array $attributes = NULL)
|
||||
{
|
||||
$attributes['type'] = 'radio';
|
||||
|
||||
if ($checked === TRUE)
|
||||
{
|
||||
// Make the radio active
|
||||
$attributes['checked'] = 'checked';
|
||||
}
|
||||
|
||||
return Form::input($name, $value, $attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a textarea form input.
|
||||
*
|
||||
* echo Form::textarea('about', $about);
|
||||
*
|
||||
* @param string textarea name
|
||||
* @param string textarea body
|
||||
* @param array html attributes
|
||||
* @param boolean encode existing HTML characters
|
||||
* @return string
|
||||
* @uses HTML::attributes
|
||||
* @uses HTML::chars
|
||||
*/
|
||||
public static function textarea($name, $body = '', array $attributes = NULL, $double_encode = TRUE)
|
||||
{
|
||||
// Set the input name
|
||||
$attributes['name'] = $name;
|
||||
|
||||
// Add default rows and cols attributes (required)
|
||||
$attributes += array('rows' => 10, 'cols' => 50);
|
||||
|
||||
return '<textarea'.HTML::attributes($attributes).'>'.HTML::chars($body, $double_encode).'</textarea>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a select form input.
|
||||
*
|
||||
* echo Form::select('country', $countries, $country);
|
||||
*
|
||||
* [!!] Support for multiple selected options was added in v3.0.7.
|
||||
*
|
||||
* @param string input name
|
||||
* @param array available options
|
||||
* @param mixed selected option string, or an array of selected options
|
||||
* @param array html attributes
|
||||
* @return string
|
||||
* @uses HTML::attributes
|
||||
*/
|
||||
public static function select($name, array $options = NULL, $selected = NULL, array $attributes = NULL)
|
||||
{
|
||||
// Set the input name
|
||||
$attributes['name'] = $name;
|
||||
|
||||
if (is_array($selected))
|
||||
{
|
||||
// This is a multi-select, god save us!
|
||||
$attributes['multiple'] = 'multiple';
|
||||
}
|
||||
|
||||
if ( ! is_array($selected))
|
||||
{
|
||||
if ($selected === NULL)
|
||||
{
|
||||
// Use an empty array
|
||||
$selected = array();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Convert the selected options to an array
|
||||
$selected = array((string) $selected);
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($options))
|
||||
{
|
||||
// There are no options
|
||||
$options = '';
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach ($options as $value => $name)
|
||||
{
|
||||
if (is_array($name))
|
||||
{
|
||||
// Create a new optgroup
|
||||
$group = array('label' => $value);
|
||||
|
||||
// Create a new list of options
|
||||
$_options = array();
|
||||
|
||||
foreach ($name as $_value => $_name)
|
||||
{
|
||||
// Force value to be string
|
||||
$_value = (string) $_value;
|
||||
|
||||
// Create a new attribute set for this option
|
||||
$option = array('value' => $_value);
|
||||
|
||||
if (in_array($_value, $selected))
|
||||
{
|
||||
// This option is selected
|
||||
$option['selected'] = 'selected';
|
||||
}
|
||||
|
||||
// Change the option to the HTML string
|
||||
$_options[] = '<option'.HTML::attributes($option).'>'.HTML::chars($_name, FALSE).'</option>';
|
||||
}
|
||||
|
||||
// Compile the options into a string
|
||||
$_options = "\n".implode("\n", $_options)."\n";
|
||||
|
||||
$options[$value] = '<optgroup'.HTML::attributes($group).'>'.$_options.'</optgroup>';
|
||||
}
|
||||
else
|
||||
{
|
||||
// Force value to be string
|
||||
$value = (string) $value;
|
||||
|
||||
// Create a new attribute set for this option
|
||||
$option = array('value' => $value);
|
||||
|
||||
if (in_array($value, $selected))
|
||||
{
|
||||
// This option is selected
|
||||
$option['selected'] = 'selected';
|
||||
}
|
||||
|
||||
// Change the option to the HTML string
|
||||
$options[$value] = '<option'.HTML::attributes($option).'>'.HTML::chars($name, FALSE).'</option>';
|
||||
}
|
||||
}
|
||||
|
||||
// Compile the options into a single string
|
||||
$options = "\n".implode("\n", $options)."\n";
|
||||
}
|
||||
|
||||
return '<select'.HTML::attributes($attributes).'>'.$options.'</select>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a submit form input.
|
||||
*
|
||||
* echo Form::submit(NULL, 'Login');
|
||||
*
|
||||
* @param string input name
|
||||
* @param string input value
|
||||
* @param array html attributes
|
||||
* @return string
|
||||
* @uses Form::input
|
||||
*/
|
||||
public static function submit($name, $value, array $attributes = NULL)
|
||||
{
|
||||
$attributes['type'] = 'submit';
|
||||
|
||||
return Form::input($name, $value, $attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a image form input.
|
||||
*
|
||||
* echo Form::image(NULL, NULL, array('src' => 'media/img/login.png'));
|
||||
*
|
||||
* @param string input name
|
||||
* @param string input value
|
||||
* @param array html attributes
|
||||
* @param boolean add index file to URL?
|
||||
* @return string
|
||||
* @uses Form::input
|
||||
*/
|
||||
public static function image($name, $value, array $attributes = NULL, $index = FALSE)
|
||||
{
|
||||
if ( ! empty($attributes['src']))
|
||||
{
|
||||
if (strpos($attributes['src'], '://') === FALSE)
|
||||
{
|
||||
// Add the base URL
|
||||
$attributes['src'] = URL::base($index).$attributes['src'];
|
||||
}
|
||||
}
|
||||
|
||||
$attributes['type'] = 'image';
|
||||
|
||||
return Form::input($name, $value, $attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a button form input. Note that the body of a button is NOT escaped,
|
||||
* to allow images and other HTML to be used.
|
||||
*
|
||||
* echo Form::button('save', 'Save Profile', array('type' => 'submit'));
|
||||
*
|
||||
* @param string input name
|
||||
* @param string input value
|
||||
* @param array html attributes
|
||||
* @return string
|
||||
* @uses HTML::attributes
|
||||
*/
|
||||
public static function button($name, $body, array $attributes = NULL)
|
||||
{
|
||||
// Set the input name
|
||||
$attributes['name'] = $name;
|
||||
|
||||
return '<button'.HTML::attributes($attributes).'>'.$body.'</button>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a form label. Label text is not automatically translated.
|
||||
*
|
||||
* echo Form::label('username', 'Username');
|
||||
*
|
||||
* @param string target input
|
||||
* @param string label text
|
||||
* @param array html attributes
|
||||
* @return string
|
||||
* @uses HTML::attributes
|
||||
*/
|
||||
public static function label($input, $text = NULL, array $attributes = NULL)
|
||||
{
|
||||
if ($text === NULL)
|
||||
{
|
||||
// Use the input name as the text
|
||||
$text = ucwords(preg_replace('/[\W_]+/', ' ', $input));
|
||||
}
|
||||
|
||||
// Set the label target
|
||||
$attributes['for'] = $input;
|
||||
|
||||
return '<label'.HTML::attributes($attributes).'>'.$text.'</label>';
|
||||
}
|
||||
|
||||
} // End form
|
145
includes/kohana/system/classes/kohana/fragment.php
Normal file
145
includes/kohana/system/classes/kohana/fragment.php
Normal file
@@ -0,0 +1,145 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
/**
|
||||
* View fragment caching. This is primarily used to cache small parts of a view
|
||||
* that rarely change. For instance, you may want to cache the footer of your
|
||||
* template because it has very little dynamic content. Or you could cache a
|
||||
* user profile page and delete the fragment when the user updates.
|
||||
*
|
||||
* For obvious reasons, fragment caching should not be applied to any
|
||||
* content that contains forms.
|
||||
*
|
||||
* [!!] Multiple language (I18n) support was added in v3.0.4.
|
||||
*
|
||||
* @package Kohana
|
||||
* @category Helpers
|
||||
* @author Kohana Team
|
||||
* @copyright (c) 2009-2010 Kohana Team
|
||||
* @license http://kohanaphp.com/license
|
||||
* @uses Kohana::cache
|
||||
*/
|
||||
class Kohana_Fragment {
|
||||
|
||||
/**
|
||||
* @var integer default number of seconds to cache for
|
||||
*/
|
||||
public static $lifetime = 30;
|
||||
|
||||
/**
|
||||
* @var boolean use multilingual fragment support?
|
||||
*/
|
||||
public static $i18n = FALSE;
|
||||
|
||||
// List of buffer => cache key
|
||||
protected static $_caches = array();
|
||||
|
||||
/**
|
||||
* Generate the cache key name for a fragment.
|
||||
*
|
||||
* $key = Fragment::_cache_key('footer', TRUE);
|
||||
*
|
||||
* @param string fragment name
|
||||
* @param boolean multilingual fragment support
|
||||
* @return string
|
||||
* @uses I18n::lang
|
||||
* @since 3.0.4
|
||||
*/
|
||||
protected static function _cache_key($name, $i18n = NULL)
|
||||
{
|
||||
if ($i18n === NULL)
|
||||
{
|
||||
// Use the default setting
|
||||
$i18n = Fragment::$i18n;
|
||||
}
|
||||
|
||||
// Language prefix for cache key
|
||||
$i18n = ($i18n === TRUE) ? I18n::lang() : '';
|
||||
|
||||
// Note: $i18n and $name need to be delimited to prevent naming collisions
|
||||
return 'Fragment::cache('.$i18n.'+'.$name.')';
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a fragment from cache and display it. Multiple fragments can
|
||||
* be nested with different life times.
|
||||
*
|
||||
* if ( ! Fragment::load('footer')) {
|
||||
* // Anything that is echo'ed here will be saved
|
||||
* Fragment::save();
|
||||
* }
|
||||
*
|
||||
* @param string fragment name
|
||||
* @param integer fragment cache lifetime
|
||||
* @param boolean multilingual fragment support
|
||||
* @return boolean
|
||||
*/
|
||||
public static function load($name, $lifetime = NULL, $i18n = NULL)
|
||||
{
|
||||
// Set the cache lifetime
|
||||
$lifetime = ($lifetime === NULL) ? Fragment::$lifetime : (int) $lifetime;
|
||||
|
||||
// Get the cache key name
|
||||
$cache_key = Fragment::_cache_key($name, $i18n);
|
||||
|
||||
if ($fragment = Kohana::cache($cache_key, NULL, $lifetime))
|
||||
{
|
||||
// Display the cached fragment now
|
||||
echo $fragment;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Start the output buffer
|
||||
ob_start();
|
||||
|
||||
// Store the cache key by the buffer level
|
||||
Fragment::$_caches[ob_get_level()] = $cache_key;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the currently open fragment in the cache.
|
||||
*
|
||||
* Fragment::save();
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function save()
|
||||
{
|
||||
// Get the buffer level
|
||||
$level = ob_get_level();
|
||||
|
||||
if (isset(Fragment::$_caches[$level]))
|
||||
{
|
||||
// Get the cache key based on the level
|
||||
$cache_key = Fragment::$_caches[$level];
|
||||
|
||||
// Delete the cache key, we don't need it anymore
|
||||
unset(Fragment::$_caches[$level]);
|
||||
|
||||
// Get the output buffer and display it at the same time
|
||||
$fragment = ob_get_flush();
|
||||
|
||||
// Cache the fragment
|
||||
Kohana::cache($cache_key, $fragment);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a cached fragment.
|
||||
*
|
||||
* Fragment::delete($key);
|
||||
*
|
||||
* @param string fragment name
|
||||
* @param boolean multilingual fragment support
|
||||
* @return void
|
||||
*/
|
||||
public static function delete($name, $i18n = NULL)
|
||||
{
|
||||
// Invalid the cache
|
||||
Kohana::cache(Fragment::_cache_key($name, $i18n), NULL, -3600);
|
||||
}
|
||||
|
||||
} // End Fragment
|
367
includes/kohana/system/classes/kohana/html.php
Normal file
367
includes/kohana/system/classes/kohana/html.php
Normal file
@@ -0,0 +1,367 @@
|
||||
<?php defined('SYSPATH') or die('No direct access allowed.');
|
||||
/**
|
||||
* HTML helper class. Provides generic methods for generating various HTML
|
||||
* tags and making output HTML safe.
|
||||
*
|
||||
* @package Kohana
|
||||
* @category Helpers
|
||||
* @author Kohana Team
|
||||
* @copyright (c) 2007-2010 Kohana Team
|
||||
* @license http://kohanaphp.com/license
|
||||
*/
|
||||
class Kohana_HTML {
|
||||
|
||||
/**
|
||||
* @var array preferred order of attributes
|
||||
*/
|
||||
public static $attribute_order = array
|
||||
(
|
||||
'action',
|
||||
'method',
|
||||
'type',
|
||||
'id',
|
||||
'name',
|
||||
'value',
|
||||
'href',
|
||||
'src',
|
||||
'width',
|
||||
'height',
|
||||
'cols',
|
||||
'rows',
|
||||
'size',
|
||||
'maxlength',
|
||||
'rel',
|
||||
'media',
|
||||
'accept-charset',
|
||||
'accept',
|
||||
'tabindex',
|
||||
'accesskey',
|
||||
'alt',
|
||||
'title',
|
||||
'class',
|
||||
'style',
|
||||
'selected',
|
||||
'checked',
|
||||
'readonly',
|
||||
'disabled',
|
||||
);
|
||||
|
||||
/**
|
||||
* @var boolean automatically target external URLs to a new window?
|
||||
*/
|
||||
public static $windowed_urls = FALSE;
|
||||
|
||||
/**
|
||||
* Convert special characters to HTML entities. All untrusted content
|
||||
* should be passed through this method to prevent XSS injections.
|
||||
*
|
||||
* echo HTML::chars($username);
|
||||
*
|
||||
* @param string string to convert
|
||||
* @param boolean encode existing entities
|
||||
* @return string
|
||||
*/
|
||||
public static function chars($value, $double_encode = TRUE)
|
||||
{
|
||||
return htmlspecialchars((string) $value, ENT_QUOTES, Kohana::$charset, $double_encode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert all applicable characters to HTML entities. All characters
|
||||
* that cannot be represented in HTML with the current character set
|
||||
* will be converted to entities.
|
||||
*
|
||||
* echo HTML::entities($username);
|
||||
*
|
||||
* @param string string to convert
|
||||
* @param boolean encode existing entities
|
||||
* @return string
|
||||
*/
|
||||
public static function entities($value, $double_encode = TRUE)
|
||||
{
|
||||
return htmlentities((string) $value, ENT_QUOTES, Kohana::$charset, $double_encode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create HTML link anchors. Note that the title is not escaped, to allow
|
||||
* HTML elements within links (images, etc).
|
||||
*
|
||||
* echo HTML::anchor('/user/profile', 'My Profile');
|
||||
*
|
||||
* @param string URL or URI string
|
||||
* @param string link text
|
||||
* @param array HTML anchor attributes
|
||||
* @param string use a specific protocol
|
||||
* @return string
|
||||
* @uses URL::base
|
||||
* @uses URL::site
|
||||
* @uses HTML::attributes
|
||||
*/
|
||||
public static function anchor($uri, $title = NULL, array $attributes = NULL, $protocol = NULL)
|
||||
{
|
||||
if ($title === NULL)
|
||||
{
|
||||
// Use the URI as the title
|
||||
$title = $uri;
|
||||
}
|
||||
|
||||
if ($uri === '')
|
||||
{
|
||||
// Only use the base URL
|
||||
$uri = URL::base(FALSE, $protocol);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (strpos($uri, '://') !== FALSE)
|
||||
{
|
||||
if (HTML::$windowed_urls === TRUE AND empty($attributes['target']))
|
||||
{
|
||||
// Make the link open in a new window
|
||||
$attributes['target'] = '_blank';
|
||||
}
|
||||
}
|
||||
elseif ($uri[0] !== '#')
|
||||
{
|
||||
// Make the URI absolute for non-id anchors
|
||||
$uri = URL::site($uri, $protocol);
|
||||
}
|
||||
}
|
||||
|
||||
// Add the sanitized link to the attributes
|
||||
$attributes['href'] = $uri;
|
||||
|
||||
return '<a'.HTML::attributes($attributes).'>'.$title.'</a>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an HTML anchor to a file. Note that the title is not escaped,
|
||||
* to allow HTML elements within links (images, etc).
|
||||
*
|
||||
* echo HTML::file_anchor('media/doc/user_guide.pdf', 'User Guide');
|
||||
*
|
||||
* @param string name of file to link to
|
||||
* @param string link text
|
||||
* @param array HTML anchor attributes
|
||||
* @param string non-default protocol, eg: ftp
|
||||
* @return string
|
||||
* @uses URL::base
|
||||
* @uses HTML::attributes
|
||||
*/
|
||||
public static function file_anchor($file, $title = NULL, array $attributes = NULL, $protocol = NULL)
|
||||
{
|
||||
if ($title === NULL)
|
||||
{
|
||||
// Use the file name as the title
|
||||
$title = basename($file);
|
||||
}
|
||||
|
||||
// Add the file link to the attributes
|
||||
$attributes['href'] = URL::base(FALSE, $protocol).$file;
|
||||
|
||||
return '<a'.HTML::attributes($attributes).'>'.$title.'</a>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an obfuscated version of a string. Text passed through this
|
||||
* method is less likely to be read by web crawlers and robots, which can
|
||||
* be helpful for spam prevention, but can prevent legitimate robots from
|
||||
* reading your content.
|
||||
*
|
||||
* echo HTML::obfuscate($text);
|
||||
*
|
||||
* @param string string to obfuscate
|
||||
* @return string
|
||||
* @since 3.0.3
|
||||
*/
|
||||
public static function obfuscate($string)
|
||||
{
|
||||
$safe = '';
|
||||
foreach (str_split($string) as $letter)
|
||||
{
|
||||
switch (rand(1, 3))
|
||||
{
|
||||
// HTML entity code
|
||||
case 1: $safe .= '&#'.ord($letter).';'; break;
|
||||
// Hex character code
|
||||
case 2: $safe .= '&#x'.dechex(ord($letter)).';'; break;
|
||||
// Raw (no) encoding
|
||||
case 3: $safe .= $letter;
|
||||
}
|
||||
}
|
||||
|
||||
return $safe;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an obfuscated version of an email address. Helps prevent spam
|
||||
* robots from finding email addresses.
|
||||
*
|
||||
* echo HTML::email($address);
|
||||
*
|
||||
* @param string email address
|
||||
* @return string
|
||||
* @uses HTML::obfuscate
|
||||
*/
|
||||
public static function email($email)
|
||||
{
|
||||
// Make sure the at sign is always obfuscated
|
||||
return str_replace('@', '@', HTML::obfuscate($email));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an email (mailto:) anchor. Note that the title is not escaped,
|
||||
* to allow HTML elements within links (images, etc).
|
||||
*
|
||||
* echo HTML::mailto($address);
|
||||
*
|
||||
* @param string email address to send to
|
||||
* @param string link text
|
||||
* @param array HTML anchor attributes
|
||||
* @return string
|
||||
* @uses HTML::email
|
||||
* @uses HTML::attributes
|
||||
*/
|
||||
public static function mailto($email, $title = NULL, array $attributes = NULL)
|
||||
{
|
||||
// Obfuscate email address
|
||||
$email = HTML::email($email);
|
||||
|
||||
if ($title === NULL)
|
||||
{
|
||||
// Use the email address as the title
|
||||
$title = $email;
|
||||
}
|
||||
|
||||
return '<a href="mailto:'.$email.'"'.HTML::attributes($attributes).'>'.$title.'</a>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a style sheet link element.
|
||||
*
|
||||
* echo HTML::style('media/css/screen.css');
|
||||
*
|
||||
* @param string file name
|
||||
* @param array default attributes
|
||||
* @param boolean include the index page
|
||||
* @return string
|
||||
* @uses URL::base
|
||||
* @uses HTML::attributes
|
||||
*/
|
||||
public static function style($file, array $attributes = NULL, $index = FALSE)
|
||||
{
|
||||
if (strpos($file, '://') === FALSE)
|
||||
{
|
||||
// Add the base URL
|
||||
$file = URL::base($index).$file;
|
||||
}
|
||||
|
||||
// Set the stylesheet link
|
||||
$attributes['href'] = $file;
|
||||
|
||||
// Set the stylesheet rel
|
||||
$attributes['rel'] = 'stylesheet';
|
||||
|
||||
// Set the stylesheet type
|
||||
$attributes['type'] = 'text/css';
|
||||
|
||||
return '<link'.HTML::attributes($attributes).' />';
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a script link.
|
||||
*
|
||||
* echo HTML::script('media/js/jquery.min.js');
|
||||
*
|
||||
* @param string file name
|
||||
* @param array default attributes
|
||||
* @param boolean include the index page
|
||||
* @return string
|
||||
* @uses URL::base
|
||||
* @uses HTML::attributes
|
||||
*/
|
||||
public static function script($file, array $attributes = NULL, $index = FALSE)
|
||||
{
|
||||
if (strpos($file, '://') === FALSE)
|
||||
{
|
||||
// Add the base URL
|
||||
$file = URL::base($index).$file;
|
||||
}
|
||||
|
||||
// Set the script link
|
||||
$attributes['src'] = $file;
|
||||
|
||||
// Set the script type
|
||||
$attributes['type'] = 'text/javascript';
|
||||
|
||||
return '<script'.HTML::attributes($attributes).'></script>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a image link.
|
||||
*
|
||||
* echo HTML::image('media/img/logo.png', array('alt' => 'My Company'));
|
||||
*
|
||||
* @param string file name
|
||||
* @param array default attributes
|
||||
* @return string
|
||||
* @uses URL::base
|
||||
* @uses HTML::attributes
|
||||
*/
|
||||
public static function image($file, array $attributes = NULL, $index = FALSE)
|
||||
{
|
||||
if (strpos($file, '://') === FALSE)
|
||||
{
|
||||
// Add the base URL
|
||||
$file = URL::base($index).$file;
|
||||
}
|
||||
|
||||
// Add the image link
|
||||
$attributes['src'] = $file;
|
||||
|
||||
return '<img'.HTML::attributes($attributes).' />';
|
||||
}
|
||||
|
||||
/**
|
||||
* Compiles an array of HTML attributes into an attribute string.
|
||||
* Attributes will be sorted using HTML::$attribute_order for consistency.
|
||||
*
|
||||
* echo '<div'.HTML::attributes($attrs).'>'.$content.'</div>';
|
||||
*
|
||||
* @param array attribute list
|
||||
* @return string
|
||||
*/
|
||||
public static function attributes(array $attributes = NULL)
|
||||
{
|
||||
if (empty($attributes))
|
||||
return '';
|
||||
|
||||
$sorted = array();
|
||||
foreach (HTML::$attribute_order as $key)
|
||||
{
|
||||
if (isset($attributes[$key]))
|
||||
{
|
||||
// Add the attribute to the sorted list
|
||||
$sorted[$key] = $attributes[$key];
|
||||
}
|
||||
}
|
||||
|
||||
// Combine the sorted attributes
|
||||
$attributes = $sorted + $attributes;
|
||||
|
||||
$compiled = '';
|
||||
foreach ($attributes as $key => $value)
|
||||
{
|
||||
if ($value === NULL)
|
||||
{
|
||||
// Skip attributes that have NULL values
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add the attribute value
|
||||
$compiled .= ' '.$key.'="'.HTML::chars($value).'"';
|
||||
}
|
||||
|
||||
return $compiled;
|
||||
}
|
||||
|
||||
} // End html
|
132
includes/kohana/system/classes/kohana/i18n.php
Normal file
132
includes/kohana/system/classes/kohana/i18n.php
Normal file
@@ -0,0 +1,132 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
/**
|
||||
* Internationalization (i18n) class. Provides language loading and translation
|
||||
* methods without dependencies on [gettext](http://php.net/gettext).
|
||||
*
|
||||
* Typically this class would never be used directly, but used via the __()
|
||||
* function, which loads the message and replaces parameters:
|
||||
*
|
||||
* // Display a translated message
|
||||
* echo __('Hello, world');
|
||||
*
|
||||
* // With parameter replacement
|
||||
* echo __('Hello, :user', array(':user' => $username));
|
||||
*
|
||||
* [!!] The __() function is declared in `SYSPATH/base.php`.
|
||||
*
|
||||
* @package Kohana
|
||||
* @category Base
|
||||
* @author Kohana Team
|
||||
* @copyright (c) 2008-2009 Kohana Team
|
||||
* @license http://kohanaphp.com/license
|
||||
*/
|
||||
class Kohana_I18n {
|
||||
|
||||
/**
|
||||
* @var string target language: en-us, es-es, zh-cn, etc
|
||||
*/
|
||||
public static $lang = 'en-us';
|
||||
|
||||
// Cache of loaded languages
|
||||
protected static $_cache = array();
|
||||
|
||||
/**
|
||||
* Get and set the target language.
|
||||
*
|
||||
* // Get the current language
|
||||
* $lang = I18n::lang();
|
||||
*
|
||||
* // Change the current language to Spanish
|
||||
* I18n::lang('es-es');
|
||||
*
|
||||
* @param string new language setting
|
||||
* @return string
|
||||
* @since 3.0.2
|
||||
*/
|
||||
public static function lang($lang = NULL)
|
||||
{
|
||||
if ($lang)
|
||||
{
|
||||
// Normalize the language
|
||||
I18n::$lang = strtolower(str_replace(array(' ', '_'), '-', $lang));
|
||||
}
|
||||
|
||||
return I18n::$lang;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns translation of a string. If no translation exists, the original
|
||||
* string will be returned. No parameters are replaced.
|
||||
*
|
||||
* $hello = I18n::get('Hello friends, my name is :name');
|
||||
*
|
||||
* @param string text to translate
|
||||
* @param string target language
|
||||
* @return string
|
||||
*/
|
||||
public static function get($string, $lang = NULL)
|
||||
{
|
||||
if ( ! $lang)
|
||||
{
|
||||
// Use the global target language
|
||||
$lang = I18n::$lang;
|
||||
}
|
||||
|
||||
// Load the translation table for this language
|
||||
$table = I18n::load($lang);
|
||||
|
||||
// Return the translated string if it exists
|
||||
return isset($table[$string]) ? $table[$string] : $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the translation table for a given language.
|
||||
*
|
||||
* // Get all defined Spanish messages
|
||||
* $messages = I18n::load('es-es');
|
||||
*
|
||||
* @param string language to load
|
||||
* @return array
|
||||
*/
|
||||
public static function load($lang)
|
||||
{
|
||||
if (isset(I18n::$_cache[$lang]))
|
||||
{
|
||||
return I18n::$_cache[$lang];
|
||||
}
|
||||
|
||||
// New translation table
|
||||
$table = array();
|
||||
|
||||
// Split the language: language, region, locale, etc
|
||||
$parts = explode('-', $lang);
|
||||
|
||||
do
|
||||
{
|
||||
// Create a path for this set of parts
|
||||
$path = implode(DIRECTORY_SEPARATOR, $parts);
|
||||
|
||||
if ($files = Kohana::find_file('i18n', $path, NULL, TRUE))
|
||||
{
|
||||
$t = array();
|
||||
foreach ($files as $file)
|
||||
{
|
||||
// Merge the language strings into the sub table
|
||||
$t = array_merge($t, Kohana::load($file));
|
||||
}
|
||||
|
||||
// Append the sub table, preventing less specific language
|
||||
// files from overloading more specific files
|
||||
$table += $t;
|
||||
}
|
||||
|
||||
// Remove the last part
|
||||
array_pop($parts);
|
||||
}
|
||||
while ($parts);
|
||||
|
||||
// Cache the translation table locally
|
||||
return I18n::$_cache[$lang] = $table;
|
||||
}
|
||||
|
||||
} // End I18n
|
237
includes/kohana/system/classes/kohana/inflector.php
Normal file
237
includes/kohana/system/classes/kohana/inflector.php
Normal file
@@ -0,0 +1,237 @@
|
||||
<?php defined('SYSPATH') or die('No direct access allowed.');
|
||||
/**
|
||||
* Inflector helper class. Inflection is changing the form of a word based on
|
||||
* the context it is used in. For example, changing a word into a plural form.
|
||||
*
|
||||
* [!!] Inflection is only tested with English, and is will not work with other languages.
|
||||
*
|
||||
* @package Kohana
|
||||
* @category Helpers
|
||||
* @author Kohana Team
|
||||
* @copyright (c) 2007-2009 Kohana Team
|
||||
* @license http://kohanaphp.com/license
|
||||
*/
|
||||
class Kohana_Inflector {
|
||||
|
||||
// Cached inflections
|
||||
protected static $cache = array();
|
||||
|
||||
// Uncountable and irregular words
|
||||
protected static $uncountable;
|
||||
protected static $irregular;
|
||||
|
||||
/**
|
||||
* Checks if a word is defined as uncountable. An uncountable word has a
|
||||
* single form. For instance, one "fish" and many "fish", not "fishes".
|
||||
*
|
||||
* Inflector::uncountable('fish'); // TRUE
|
||||
* Inflector::uncountable('cat'); // FALSE
|
||||
*
|
||||
* If you find a word is being pluralized improperly, it has probably not
|
||||
* been defined as uncountable in `config/inflector.php`. If this is the
|
||||
* case, please report [an issue](http://dev.kohanaphp.com/projects/kohana3/issues).
|
||||
*
|
||||
* @param string word to check
|
||||
* @return boolean
|
||||
*/
|
||||
public static function uncountable($str)
|
||||
{
|
||||
if (Inflector::$uncountable === NULL)
|
||||
{
|
||||
// Cache uncountables
|
||||
Inflector::$uncountable = Kohana::config('inflector')->uncountable;
|
||||
|
||||
// Make uncountables mirrored
|
||||
Inflector::$uncountable = array_combine(Inflector::$uncountable, Inflector::$uncountable);
|
||||
}
|
||||
|
||||
return isset(Inflector::$uncountable[strtolower($str)]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a plural word singular.
|
||||
*
|
||||
* echo Inflector::singular('cats'); // "cat"
|
||||
* echo Inflector::singular('fish'); // "fish", uncountable
|
||||
*
|
||||
* You can also provide the count to make inflection more intelligent.
|
||||
* In this case, it will only return the singular value if the count is
|
||||
* greater than one and not zero.
|
||||
*
|
||||
* echo Inflector::singular('cats', 2); // "cats"
|
||||
*
|
||||
* [!!] Special inflections are defined in `config/inflector.php`.
|
||||
*
|
||||
* @param string word to singularize
|
||||
* @param integer count of thing
|
||||
* @return string
|
||||
* @uses Inflector::uncountable
|
||||
*/
|
||||
public static function singular($str, $count = NULL)
|
||||
{
|
||||
// $count should always be a float
|
||||
$count = ($count === NULL) ? 1.0 : (float) $count;
|
||||
|
||||
// Do nothing when $count is not 1
|
||||
if ($count != 1)
|
||||
return $str;
|
||||
|
||||
// Remove garbage
|
||||
$str = strtolower(trim($str));
|
||||
|
||||
// Cache key name
|
||||
$key = 'singular_'.$str.$count;
|
||||
|
||||
if (isset(Inflector::$cache[$key]))
|
||||
return Inflector::$cache[$key];
|
||||
|
||||
if (Inflector::uncountable($str))
|
||||
return Inflector::$cache[$key] = $str;
|
||||
|
||||
if (empty(Inflector::$irregular))
|
||||
{
|
||||
// Cache irregular words
|
||||
Inflector::$irregular = Kohana::config('inflector')->irregular;
|
||||
}
|
||||
|
||||
if ($irregular = array_search($str, Inflector::$irregular))
|
||||
{
|
||||
$str = $irregular;
|
||||
}
|
||||
elseif (preg_match('/us$/', $str))
|
||||
{
|
||||
// http://en.wikipedia.org/wiki/Plural_form_of_words_ending_in_-us
|
||||
// Already singular, do nothing
|
||||
}
|
||||
elseif (preg_match('/[sxz]es$/', $str) OR preg_match('/[^aeioudgkprt]hes$/', $str))
|
||||
{
|
||||
// Remove "es"
|
||||
$str = substr($str, 0, -2);
|
||||
}
|
||||
elseif (preg_match('/[^aeiou]ies$/', $str))
|
||||
{
|
||||
// Replace "ies" with "y"
|
||||
$str = substr($str, 0, -3).'y';
|
||||
}
|
||||
elseif (substr($str, -1) === 's' AND substr($str, -2) !== 'ss')
|
||||
{
|
||||
// Remove singular "s"
|
||||
$str = substr($str, 0, -1);
|
||||
}
|
||||
|
||||
return Inflector::$cache[$key] = $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a singular word plural.
|
||||
*
|
||||
* echo Inflector::plural('fish'); // "fish", uncountable
|
||||
* echo Inflector::plural('cat'); // "cats"
|
||||
*
|
||||
* You can also provide the count to make inflection more intelligent.
|
||||
* In this case, it will only return the plural value if the count is
|
||||
* not one.
|
||||
*
|
||||
* echo Inflector::singular('cats', 3); // "cats"
|
||||
*
|
||||
* [!!] Special inflections are defined in `config/inflector.php`.
|
||||
*
|
||||
* @param string word to pluralize
|
||||
* @param integer count of thing
|
||||
* @return string
|
||||
* @uses Inflector::uncountable
|
||||
*/
|
||||
public static function plural($str, $count = NULL)
|
||||
{
|
||||
// $count should always be a float
|
||||
$count = ($count === NULL) ? 0.0 : (float) $count;
|
||||
|
||||
// Do nothing with singular
|
||||
if ($count == 1)
|
||||
return $str;
|
||||
|
||||
// Remove garbage
|
||||
$str = strtolower(trim($str));
|
||||
|
||||
// Cache key name
|
||||
$key = 'plural_'.$str.$count;
|
||||
|
||||
if (isset(Inflector::$cache[$key]))
|
||||
return Inflector::$cache[$key];
|
||||
|
||||
if (Inflector::uncountable($str))
|
||||
return Inflector::$cache[$key] = $str;
|
||||
|
||||
if (empty(Inflector::$irregular))
|
||||
{
|
||||
// Cache irregular words
|
||||
Inflector::$irregular = Kohana::config('inflector')->irregular;
|
||||
}
|
||||
|
||||
if (isset(Inflector::$irregular[$str]))
|
||||
{
|
||||
$str = Inflector::$irregular[$str];
|
||||
}
|
||||
elseif (preg_match('/[sxz]$/', $str) OR preg_match('/[^aeioudgkprt]h$/', $str))
|
||||
{
|
||||
$str .= 'es';
|
||||
}
|
||||
elseif (preg_match('/[^aeiou]y$/', $str))
|
||||
{
|
||||
// Change "y" to "ies"
|
||||
$str = substr_replace($str, 'ies', -1);
|
||||
}
|
||||
else
|
||||
{
|
||||
$str .= 's';
|
||||
}
|
||||
|
||||
// Set the cache and return
|
||||
return Inflector::$cache[$key] = $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a phrase camel case. Spaces and underscores will be removed.
|
||||
*
|
||||
* $str = Inflector::camelize('mother cat'); // "motherCat"
|
||||
* $str = Inflector::camelize('kittens in bed'); // "kittensInBed"
|
||||
*
|
||||
* @param string phrase to camelize
|
||||
* @return string
|
||||
*/
|
||||
public static function camelize($str)
|
||||
{
|
||||
$str = 'x'.strtolower(trim($str));
|
||||
$str = ucwords(preg_replace('/[\s_]+/', ' ', $str));
|
||||
|
||||
return substr(str_replace(' ', '', $str), 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a phrase underscored instead of spaced.
|
||||
*
|
||||
* $str = Inflector::underscore('five cats'); // "five_cats";
|
||||
*
|
||||
* @param string phrase to underscore
|
||||
* @return string
|
||||
*/
|
||||
public static function underscore($str)
|
||||
{
|
||||
return preg_replace('/\s+/', '_', trim($str));
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes an underscored or dashed phrase human-readable.
|
||||
*
|
||||
* $str = Inflector::humanize('kittens-are-cats'); // "kittens are cats"
|
||||
* $str = Inflector::humanize('dogs_as_well'); // "dogs as well"
|
||||
*
|
||||
* @param string phrase to make human-readable
|
||||
* @return string
|
||||
*/
|
||||
public static function humanize($str)
|
||||
{
|
||||
return preg_replace('/[_-]+/', ' ', trim($str));
|
||||
}
|
||||
|
||||
} // End Inflector
|
185
includes/kohana/system/classes/kohana/log.php
Normal file
185
includes/kohana/system/classes/kohana/log.php
Normal file
@@ -0,0 +1,185 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
/**
|
||||
* Message logging with observer-based log writing.
|
||||
*
|
||||
* [!!] This class does not support extensions, only additional writers.
|
||||
*
|
||||
* @package Kohana
|
||||
* @category Logging
|
||||
* @author Kohana Team
|
||||
* @copyright (c) 2008-2009 Kohana Team
|
||||
* @license http://kohanaphp.com/license
|
||||
*/
|
||||
class Kohana_Log {
|
||||
|
||||
/**
|
||||
* @var string timestamp format for log entries
|
||||
*/
|
||||
public static $timestamp = 'Y-m-d H:i:s';
|
||||
|
||||
/**
|
||||
* @var string timezone for log entries
|
||||
*/
|
||||
public static $timezone;
|
||||
|
||||
/**
|
||||
* @var boolean immediately write when logs are added
|
||||
*/
|
||||
public static $write_on_add = FALSE;
|
||||
|
||||
/**
|
||||
* @var Kohana_Log Singleton instance container
|
||||
*/
|
||||
private static $_instance;
|
||||
|
||||
/**
|
||||
* Get the singleton instance of this class and enable writing at shutdown.
|
||||
*
|
||||
* $log = Kohana_Log::instance();
|
||||
*
|
||||
* @return Kohana_Log
|
||||
*/
|
||||
public static function instance()
|
||||
{
|
||||
if (self::$_instance === NULL)
|
||||
{
|
||||
// Create a new instance
|
||||
self::$_instance = new self;
|
||||
|
||||
// Write the logs at shutdown
|
||||
register_shutdown_function(array(self::$_instance, 'write'));
|
||||
}
|
||||
|
||||
return self::$_instance;
|
||||
}
|
||||
|
||||
// List of added messages
|
||||
private $_messages = array();
|
||||
|
||||
// List of log writers
|
||||
private $_writers = array();
|
||||
|
||||
/**
|
||||
* Attaches a log writer, and optionally limits the types of messages that
|
||||
* will be written by the writer.
|
||||
*
|
||||
* $log->attach($writer);
|
||||
*
|
||||
* @param object Kohana_Log_Writer instance
|
||||
* @param array messages types to write
|
||||
* @return $this
|
||||
*/
|
||||
public function attach(Kohana_Log_Writer $writer, array $types = NULL)
|
||||
{
|
||||
$this->_writers["{$writer}"] = array
|
||||
(
|
||||
'object' => $writer,
|
||||
'types' => $types
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detaches a log writer. The same writer object must be used.
|
||||
*
|
||||
* $log->detach($writer);
|
||||
*
|
||||
* @param object Kohana_Log_Writer instance
|
||||
* @return $this
|
||||
*/
|
||||
public function detach(Kohana_Log_Writer $writer)
|
||||
{
|
||||
// Remove the writer
|
||||
unset($this->_writers["{$writer}"]);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a message to the log. Replacement values must be passed in to be
|
||||
* replaced using [strtr](http://php.net/strtr).
|
||||
*
|
||||
* $log->add('error', 'Could not locate user: :user', array(
|
||||
* ':user' => $username,
|
||||
* ));
|
||||
*
|
||||
* @param string type of message
|
||||
* @param string message body
|
||||
* @param array values to replace in the message
|
||||
* @return $this
|
||||
*/
|
||||
public function add($type, $message, array $values = NULL)
|
||||
{
|
||||
if ($values)
|
||||
{
|
||||
// Insert the values into the message
|
||||
$message = strtr($message, $values);
|
||||
}
|
||||
|
||||
// Create a new message and timestamp it
|
||||
$this->_messages[] = array
|
||||
(
|
||||
'time' => Date::formatted_time('now', self::$timestamp, self::$timezone),
|
||||
'type' => $type,
|
||||
'body' => $message,
|
||||
);
|
||||
|
||||
if (self::$write_on_add)
|
||||
{
|
||||
// Write logs as they are added
|
||||
$this->write();
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write and clear all of the messages.
|
||||
*
|
||||
* $log->write();
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function write()
|
||||
{
|
||||
if (empty($this->_messages))
|
||||
{
|
||||
// There is nothing to write, move along
|
||||
return;
|
||||
}
|
||||
|
||||
// Import all messages locally
|
||||
$messages = $this->_messages;
|
||||
|
||||
// Reset the messages array
|
||||
$this->_messages = array();
|
||||
|
||||
foreach ($this->_writers as $writer)
|
||||
{
|
||||
if (empty($writer['types']))
|
||||
{
|
||||
// Write all of the messages
|
||||
$writer['object']->write($messages);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Filtered messages
|
||||
$filtered = array();
|
||||
|
||||
foreach ($messages as $message)
|
||||
{
|
||||
if (in_array($message['type'], $writer['types']))
|
||||
{
|
||||
// Writer accepts this kind of message
|
||||
$filtered[] = $message;
|
||||
}
|
||||
}
|
||||
|
||||
// Write the filtered messages
|
||||
$writer['object']->write($filtered);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // End Kohana_Log
|
95
includes/kohana/system/classes/kohana/log/file.php
Normal file
95
includes/kohana/system/classes/kohana/log/file.php
Normal file
@@ -0,0 +1,95 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
/**
|
||||
* File log writer. Writes out messages and stores them in a YYYY/MM directory.
|
||||
*
|
||||
* @package Kohana
|
||||
* @category Logging
|
||||
* @author Kohana Team
|
||||
* @copyright (c) 2008-2009 Kohana Team
|
||||
* @license http://kohanaphp.com/license
|
||||
*/
|
||||
class Kohana_Log_File extends Kohana_Log_Writer {
|
||||
|
||||
// Directory to place log files in
|
||||
protected $_directory;
|
||||
|
||||
/**
|
||||
* Creates a new file logger. Checks that the directory exists and
|
||||
* is writable.
|
||||
*
|
||||
* $writer = new Kohana_Log_File($directory);
|
||||
*
|
||||
* @param string log directory
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($directory)
|
||||
{
|
||||
if ( ! is_dir($directory) OR ! is_writable($directory))
|
||||
{
|
||||
throw new Kohana_Exception('Directory :dir must be writable',
|
||||
array(':dir' => Kohana::debug_path($directory)));
|
||||
}
|
||||
|
||||
// Determine the directory path
|
||||
$this->_directory = realpath($directory).DIRECTORY_SEPARATOR;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes each of the messages into the log file. The log file will be
|
||||
* appended to the `YYYY/MM/DD.log.php` file, where YYYY is the current
|
||||
* year, MM is the current month, and DD is the current day.
|
||||
*
|
||||
* $writer->write($messages);
|
||||
*
|
||||
* @param array messages
|
||||
* @return void
|
||||
*/
|
||||
public function write(array $messages)
|
||||
{
|
||||
// Set the yearly directory name
|
||||
$directory = $this->_directory.date('Y').DIRECTORY_SEPARATOR;
|
||||
|
||||
if ( ! is_dir($directory))
|
||||
{
|
||||
// Create the yearly directory
|
||||
mkdir($directory, 0777);
|
||||
|
||||
// Set permissions (must be manually set to fix umask issues)
|
||||
chmod($directory, 0777);
|
||||
}
|
||||
|
||||
// Add the month to the directory
|
||||
$directory .= date('m').DIRECTORY_SEPARATOR;
|
||||
|
||||
if ( ! is_dir($directory))
|
||||
{
|
||||
// Create the yearly directory
|
||||
mkdir($directory, 0777);
|
||||
|
||||
// Set permissions (must be manually set to fix umask issues)
|
||||
chmod($directory, 0777);
|
||||
}
|
||||
|
||||
// Set the name of the log file
|
||||
$filename = $directory.date('d').EXT;
|
||||
|
||||
if ( ! file_exists($filename))
|
||||
{
|
||||
// Create the log file
|
||||
file_put_contents($filename, Kohana::FILE_SECURITY.' ?>'.PHP_EOL);
|
||||
|
||||
// Allow anyone to write to log files
|
||||
chmod($filename, 0666);
|
||||
}
|
||||
|
||||
// Set the log line format
|
||||
$format = 'time --- type: body';
|
||||
|
||||
foreach ($messages as $message)
|
||||
{
|
||||
// Write each message into the log file
|
||||
file_put_contents($filename, PHP_EOL.strtr($format, $message), FILE_APPEND);
|
||||
}
|
||||
}
|
||||
|
||||
} // End Kohana_Log_File
|
65
includes/kohana/system/classes/kohana/log/syslog.php
Normal file
65
includes/kohana/system/classes/kohana/log/syslog.php
Normal file
@@ -0,0 +1,65 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
/**
|
||||
* Syslog log writer.
|
||||
*
|
||||
* @package Kohana
|
||||
* @category Logging
|
||||
* @author Jeremy Bush
|
||||
* @copyright (c) 2010 Kohana Team
|
||||
* @license http://kohanaphp.com/license
|
||||
*/
|
||||
class Kohana_Log_Syslog extends Kohana_Log_Writer {
|
||||
|
||||
// The syslog identifier
|
||||
protected $_ident;
|
||||
|
||||
protected $_syslog_levels = array('ERROR' => LOG_ERR,
|
||||
'CRITICAL' => LOG_CRIT,
|
||||
'STRACE' => LOG_ALERT,
|
||||
'ALERT' => LOG_WARNING,
|
||||
'INFO' => LOG_INFO,
|
||||
'DEBUG' => LOG_DEBUG);
|
||||
|
||||
/**
|
||||
* Creates a new syslog logger.
|
||||
*
|
||||
* @see http://us2.php.net/openlog
|
||||
*
|
||||
* @param string syslog identifier
|
||||
* @param int facility to log to
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($ident = 'KohanaPHP', $facility = LOG_USER)
|
||||
{
|
||||
$this->_ident = $ident;
|
||||
|
||||
// Open the connection to syslog
|
||||
openlog($this->_ident, LOG_CONS, $facility);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes each of the messages into the syslog.
|
||||
*
|
||||
* @param array messages
|
||||
* @return void
|
||||
*/
|
||||
public function write(array $messages)
|
||||
{
|
||||
foreach ($messages as $message)
|
||||
{
|
||||
syslog($this->_syslog_levels[$message['type']], $message['body']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the syslog connection
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
// Close connection to syslog
|
||||
closelog();
|
||||
}
|
||||
|
||||
} // End Kohana_Log_Syslog
|
35
includes/kohana/system/classes/kohana/log/writer.php
Normal file
35
includes/kohana/system/classes/kohana/log/writer.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
/**
|
||||
* Log writer abstract class. All [Kohana_Log] writers must extend this class.
|
||||
*
|
||||
* @package Kohana
|
||||
* @category Logging
|
||||
* @author Kohana Team
|
||||
* @copyright (c) 2008-2009 Kohana Team
|
||||
* @license http://kohanaphp.com/license
|
||||
*/
|
||||
abstract class Kohana_Log_Writer {
|
||||
|
||||
/**
|
||||
* Write an array of messages.
|
||||
*
|
||||
* $writer->write($messages);
|
||||
*
|
||||
* @param array messages
|
||||
* @return void
|
||||
*/
|
||||
abstract public function write(array $messages);
|
||||
|
||||
/**
|
||||
* Allows the writer to have a unique key when stored.
|
||||
*
|
||||
* echo $writer;
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
final public function __toString()
|
||||
{
|
||||
return spl_object_hash($this);
|
||||
}
|
||||
|
||||
} // End Kohana_Log_Writer
|
58
includes/kohana/system/classes/kohana/model.php
Normal file
58
includes/kohana/system/classes/kohana/model.php
Normal file
@@ -0,0 +1,58 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
/**
|
||||
* Model base class. All models should extend this class.
|
||||
*
|
||||
* @package Kohana
|
||||
* @category Models
|
||||
* @author Kohana Team
|
||||
* @copyright (c) 2008-2009 Kohana Team
|
||||
* @license http://kohanaphp.com/license
|
||||
*/
|
||||
abstract class Kohana_Model {
|
||||
|
||||
/**
|
||||
* Create a new model instance. A [Database] instance or configuration
|
||||
* group name can be passed to the model. If no database is defined, the
|
||||
* "default" database group will be used.
|
||||
*
|
||||
* $model = Model::factory($name);
|
||||
*
|
||||
* @param string model name
|
||||
* @param mixed Database instance object or string
|
||||
* @return Model
|
||||
*/
|
||||
public static function factory($name, $db = NULL)
|
||||
{
|
||||
// Add the model prefix
|
||||
$class = 'Model_'.$name;
|
||||
|
||||
return new $class($db);
|
||||
}
|
||||
|
||||
// Database instance
|
||||
protected $_db = 'default';
|
||||
|
||||
/**
|
||||
* Loads the database.
|
||||
*
|
||||
* $model = new Foo_Model($db);
|
||||
*
|
||||
* @param mixed Database instance object or string
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($db = NULL)
|
||||
{
|
||||
if ($db !== NULL)
|
||||
{
|
||||
// Set the database instance name
|
||||
$this->_db = $db;
|
||||
}
|
||||
|
||||
if (is_string($this->_db))
|
||||
{
|
||||
// Load the database
|
||||
$this->_db = Database::instance($this->_db);
|
||||
}
|
||||
}
|
||||
|
||||
} // End Model
|
81
includes/kohana/system/classes/kohana/num.php
Normal file
81
includes/kohana/system/classes/kohana/num.php
Normal file
@@ -0,0 +1,81 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
/**
|
||||
* Number helper class. Provides additional formatting methods that for working
|
||||
* with numbers.
|
||||
*
|
||||
* @package Kohana
|
||||
* @category Helpers
|
||||
* @author Kohana Team
|
||||
* @copyright (c) 2009 Kohana Team
|
||||
* @license http://kohanaphp.com/license
|
||||
*/
|
||||
class Kohana_Num {
|
||||
|
||||
/**
|
||||
* Returns the English ordinal suffix (th, st, nd, etc) of a number.
|
||||
*
|
||||
* echo 2, Num::ordinal(2); // "2nd"
|
||||
* echo 10, Num::ordinal(10); // "10th"
|
||||
* echo 33, Num::ordinal(33); // "33rd"
|
||||
*
|
||||
* @param integer number
|
||||
* @return string
|
||||
*/
|
||||
public static function ordinal($number)
|
||||
{
|
||||
if ($number % 100 > 10 AND $number % 100 < 14)
|
||||
{
|
||||
return 'th';
|
||||
}
|
||||
|
||||
switch ($number % 10)
|
||||
{
|
||||
case 1:
|
||||
return 'st';
|
||||
case 2:
|
||||
return 'nd';
|
||||
case 3:
|
||||
return 'rd';
|
||||
default:
|
||||
return 'th';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Locale-aware number and monetary formatting.
|
||||
*
|
||||
* // In English, "1,200.05"
|
||||
* // In Spanish, "1200,05"
|
||||
* // In Portuguese, "1 200,05"
|
||||
* echo Num::format(1200.05, 2);
|
||||
*
|
||||
* // In English, "1,200.05"
|
||||
* // In Spanish, "1.200,05"
|
||||
* // In Portuguese, "1.200.05"
|
||||
* echo Num::format(1200.05, 2, TRUE);
|
||||
*
|
||||
* @param float number to format
|
||||
* @param integer decimal places
|
||||
* @param boolean monetary formatting?
|
||||
* @return string
|
||||
* @since 3.0.2
|
||||
*/
|
||||
public static function format($number, $places, $monetary = FALSE)
|
||||
{
|
||||
$info = localeconv();
|
||||
|
||||
if ($monetary)
|
||||
{
|
||||
$decimal = $info['mon_decimal_point'];
|
||||
$thousands = $info['mon_thousands_sep'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$decimal = $info['decimal_point'];
|
||||
$thousands = $info['thousands_sep'];
|
||||
}
|
||||
|
||||
return number_format($number, $places, $decimal, $thousands);
|
||||
}
|
||||
|
||||
} // End num
|
375
includes/kohana/system/classes/kohana/profiler.php
Normal file
375
includes/kohana/system/classes/kohana/profiler.php
Normal file
@@ -0,0 +1,375 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
/**
|
||||
* Provides simple benchmarking and profiling. To display the statistics that
|
||||
* have been collected, load the `profiler/stats` [View]:
|
||||
*
|
||||
* echo View::factory('profiler/stats');
|
||||
*
|
||||
* @package Kohana
|
||||
* @category Helpers
|
||||
* @author Kohana Team
|
||||
* @copyright (c) 2009-2010 Kohana Team
|
||||
* @license http://kohanaphp.com/license
|
||||
*/
|
||||
class Kohana_Profiler {
|
||||
|
||||
/**
|
||||
* @var integer maximium number of application stats to keep
|
||||
*/
|
||||
public static $rollover = 1000;
|
||||
|
||||
// Collected benchmarks
|
||||
protected static $_marks = array();
|
||||
|
||||
/**
|
||||
* Starts a new benchmark and returns a unique token. The returned token
|
||||
* _must_ be used when stopping the benchmark.
|
||||
*
|
||||
* $token = Profiler::start('test', 'profiler');
|
||||
*
|
||||
* @param string group name
|
||||
* @param string benchmark name
|
||||
* @return string
|
||||
*/
|
||||
public static function start($group, $name)
|
||||
{
|
||||
static $counter = 0;
|
||||
|
||||
// Create a unique token based on the counter
|
||||
$token = 'kp/'.base_convert($counter++, 10, 32);
|
||||
|
||||
Profiler::$_marks[$token] = array
|
||||
(
|
||||
'group' => strtolower($group),
|
||||
'name' => (string) $name,
|
||||
|
||||
// Start the benchmark
|
||||
'start_time' => microtime(TRUE),
|
||||
'start_memory' => memory_get_usage(),
|
||||
|
||||
// Set the stop keys without values
|
||||
'stop_time' => FALSE,
|
||||
'stop_memory' => FALSE,
|
||||
);
|
||||
|
||||
return $token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops a benchmark.
|
||||
*
|
||||
* Profiler::stop($token);
|
||||
*
|
||||
* @param string token
|
||||
* @return void
|
||||
*/
|
||||
public static function stop($token)
|
||||
{
|
||||
// Stop the benchmark
|
||||
Profiler::$_marks[$token]['stop_time'] = microtime(TRUE);
|
||||
Profiler::$_marks[$token]['stop_memory'] = memory_get_usage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a benchmark. If an error occurs during the benchmark, it is
|
||||
* recommended to delete the benchmark to prevent statistics from being
|
||||
* adversely affected.
|
||||
*
|
||||
* Profiler::delete($token);
|
||||
*
|
||||
* @param string token
|
||||
* @return void
|
||||
*/
|
||||
public static function delete($token)
|
||||
{
|
||||
// Remove the benchmark
|
||||
unset(Profiler::$_marks[$token]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all the benchmark tokens by group and name as an array.
|
||||
*
|
||||
* $groups = Profiler::groups();
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function groups()
|
||||
{
|
||||
$groups = array();
|
||||
|
||||
foreach (Profiler::$_marks as $token => $mark)
|
||||
{
|
||||
// Sort the tokens by the group and name
|
||||
$groups[$mark['group']][$mark['name']][] = $token;
|
||||
}
|
||||
|
||||
return $groups;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the min, max, average and total of a set of tokens as an array.
|
||||
*
|
||||
* $stats = Profiler::stats($tokens);
|
||||
*
|
||||
* @param array profiler tokens
|
||||
* @return array min, max, average, total
|
||||
* @uses Profiler::total
|
||||
*/
|
||||
public static function stats(array $tokens)
|
||||
{
|
||||
// Min and max are unknown by default
|
||||
$min = $max = array(
|
||||
'time' => NULL,
|
||||
'memory' => NULL);
|
||||
|
||||
// Total values are always integers
|
||||
$total = array(
|
||||
'time' => 0,
|
||||
'memory' => 0);
|
||||
|
||||
foreach ($tokens as $token)
|
||||
{
|
||||
// Get the total time and memory for this benchmark
|
||||
list($time, $memory) = Profiler::total($token);
|
||||
|
||||
if ($max['time'] === NULL OR $time > $max['time'])
|
||||
{
|
||||
// Set the maximum time
|
||||
$max['time'] = $time;
|
||||
}
|
||||
|
||||
if ($min['time'] === NULL OR $time < $min['time'])
|
||||
{
|
||||
// Set the minimum time
|
||||
$min['time'] = $time;
|
||||
}
|
||||
|
||||
// Increase the total time
|
||||
$total['time'] += $time;
|
||||
|
||||
if ($max['memory'] === NULL OR $memory > $max['memory'])
|
||||
{
|
||||
// Set the maximum memory
|
||||
$max['memory'] = $memory;
|
||||
}
|
||||
|
||||
if ($min['memory'] === NULL OR $memory < $min['memory'])
|
||||
{
|
||||
// Set the minimum memory
|
||||
$min['memory'] = $memory;
|
||||
}
|
||||
|
||||
// Increase the total memory
|
||||
$total['memory'] += $memory;
|
||||
}
|
||||
|
||||
// Determine the number of tokens
|
||||
$count = count($tokens);
|
||||
|
||||
// Determine the averages
|
||||
$average = array(
|
||||
'time' => $total['time'] / $count,
|
||||
'memory' => $total['memory'] / $count);
|
||||
|
||||
return array(
|
||||
'min' => $min,
|
||||
'max' => $max,
|
||||
'total' => $total,
|
||||
'average' => $average);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the min, max, average and total of profiler groups as an array.
|
||||
*
|
||||
* $stats = Profiler::group_stats('test');
|
||||
*
|
||||
* @param mixed single group name string, or array with group names; all groups by default
|
||||
* @return array min, max, average, total
|
||||
* @uses Profiler::groups
|
||||
* @uses Profiler::stats
|
||||
*/
|
||||
public static function group_stats($groups = NULL)
|
||||
{
|
||||
// Which groups do we need to calculate stats for?
|
||||
$groups = ($groups === NULL)
|
||||
? Profiler::groups()
|
||||
: array_intersect_key(Profiler::groups(), array_flip((array) $groups));
|
||||
|
||||
// All statistics
|
||||
$stats = array();
|
||||
|
||||
foreach ($groups as $group => $names)
|
||||
{
|
||||
foreach ($names as $name => $tokens)
|
||||
{
|
||||
// Store the stats for each subgroup.
|
||||
// We only need the values for "total".
|
||||
$_stats = Profiler::stats($tokens);
|
||||
$stats[$group][$name] = $_stats['total'];
|
||||
}
|
||||
}
|
||||
|
||||
// Group stats
|
||||
$groups = array();
|
||||
|
||||
foreach ($stats as $group => $names)
|
||||
{
|
||||
// Min and max are unknown by default
|
||||
$groups[$group]['min'] = $groups[$group]['max'] = array(
|
||||
'time' => NULL,
|
||||
'memory' => NULL);
|
||||
|
||||
// Total values are always integers
|
||||
$groups[$group]['total'] = array(
|
||||
'time' => 0,
|
||||
'memory' => 0);
|
||||
|
||||
foreach ($names as $total)
|
||||
{
|
||||
if ( ! isset($groups[$group]['min']['time']) OR $groups[$group]['min']['time'] > $total['time'])
|
||||
{
|
||||
// Set the minimum time
|
||||
$groups[$group]['min']['time'] = $total['time'];
|
||||
}
|
||||
if ( ! isset($groups[$group]['min']['memory']) OR $groups[$group]['min']['memory'] > $total['memory'])
|
||||
{
|
||||
// Set the minimum memory
|
||||
$groups[$group]['min']['memory'] = $total['memory'];
|
||||
}
|
||||
|
||||
if ( ! isset($groups[$group]['max']['time']) OR $groups[$group]['max']['time'] < $total['time'])
|
||||
{
|
||||
// Set the maximum time
|
||||
$groups[$group]['max']['time'] = $total['time'];
|
||||
}
|
||||
if ( ! isset($groups[$group]['max']['memory']) OR $groups[$group]['max']['memory'] < $total['memory'])
|
||||
{
|
||||
// Set the maximum memory
|
||||
$groups[$group]['max']['memory'] = $total['memory'];
|
||||
}
|
||||
|
||||
// Increase the total time and memory
|
||||
$groups[$group]['total']['time'] += $total['time'];
|
||||
$groups[$group]['total']['memory'] += $total['memory'];
|
||||
}
|
||||
|
||||
// Determine the number of names (subgroups)
|
||||
$count = count($names);
|
||||
|
||||
// Determine the averages
|
||||
$groups[$group]['average']['time'] = $groups[$group]['total']['time'] / $count;
|
||||
$groups[$group]['average']['memory'] = $groups[$group]['total']['memory'] / $count;
|
||||
}
|
||||
|
||||
return $groups;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the total execution time and memory usage of a benchmark as a list.
|
||||
*
|
||||
* list($time, $memory) = Profiler::total($token);
|
||||
*
|
||||
* @param string token
|
||||
* @return array execution time, memory
|
||||
*/
|
||||
public static function total($token)
|
||||
{
|
||||
// Import the benchmark data
|
||||
$mark = Profiler::$_marks[$token];
|
||||
|
||||
if ($mark['stop_time'] === FALSE)
|
||||
{
|
||||
// The benchmark has not been stopped yet
|
||||
$mark['stop_time'] = microtime(TRUE);
|
||||
$mark['stop_memory'] = memory_get_usage();
|
||||
}
|
||||
|
||||
return array
|
||||
(
|
||||
// Total time in seconds
|
||||
$mark['stop_time'] - $mark['start_time'],
|
||||
|
||||
// Amount of memory in bytes
|
||||
$mark['stop_memory'] - $mark['start_memory'],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the total application run time and memory usage. Caches the result
|
||||
* so that it can be compared between requests.
|
||||
*
|
||||
* list($time, $memory) = Profiler::application();
|
||||
*
|
||||
* @return array execution time, memory
|
||||
* @uses Kohana::cache
|
||||
*/
|
||||
public static function application()
|
||||
{
|
||||
// Load the stats from cache, which is valid for 1 day
|
||||
$stats = Kohana::cache('profiler_application_stats', NULL, 3600 * 24);
|
||||
|
||||
if ( ! is_array($stats) OR $stats['count'] > Profiler::$rollover)
|
||||
{
|
||||
// Initialize the stats array
|
||||
$stats = array(
|
||||
'min' => array(
|
||||
'time' => NULL,
|
||||
'memory' => NULL),
|
||||
'max' => array(
|
||||
'time' => NULL,
|
||||
'memory' => NULL),
|
||||
'total' => array(
|
||||
'time' => NULL,
|
||||
'memory' => NULL),
|
||||
'count' => 0);
|
||||
}
|
||||
|
||||
// Get the application run time
|
||||
$time = microtime(TRUE) - KOHANA_START_TIME;
|
||||
|
||||
// Get the total memory usage
|
||||
$memory = memory_get_usage() - KOHANA_START_MEMORY;
|
||||
|
||||
// Calculate max time
|
||||
if ($stats['max']['time'] === NULL OR $time > $stats['max']['time'])
|
||||
$stats['max']['time'] = $time;
|
||||
|
||||
// Calculate min time
|
||||
if ($stats['min']['time'] === NULL OR $time < $stats['min']['time'])
|
||||
$stats['min']['time'] = $time;
|
||||
|
||||
// Add to total time
|
||||
$stats['total']['time'] += $time;
|
||||
|
||||
// Calculate max memory
|
||||
if ($stats['max']['memory'] === NULL OR $memory > $stats['max']['memory'])
|
||||
$stats['max']['memory'] = $memory;
|
||||
|
||||
// Calculate min memory
|
||||
if ($stats['min']['memory'] === NULL OR $memory < $stats['min']['memory'])
|
||||
$stats['min']['memory'] = $memory;
|
||||
|
||||
// Add to total memory
|
||||
$stats['total']['memory'] += $memory;
|
||||
|
||||
// Another mark has been added to the stats
|
||||
$stats['count']++;
|
||||
|
||||
// Determine the averages
|
||||
$stats['average'] = array(
|
||||
'time' => $stats['total']['time'] / $stats['count'],
|
||||
'memory' => $stats['total']['memory'] / $stats['count']);
|
||||
|
||||
// Cache the new stats
|
||||
Kohana::cache('profiler_application_stats', $stats);
|
||||
|
||||
// Set the current application execution time and memory
|
||||
// Do NOT cache these, they are specific to the current request only
|
||||
$stats['current']['time'] = $time;
|
||||
$stats['current']['memory'] = $memory;
|
||||
|
||||
// Return the total application run time and memory usage
|
||||
return $stats;
|
||||
}
|
||||
|
||||
} // End Profiler
|
152
includes/kohana/system/classes/kohana/remote.php
Normal file
152
includes/kohana/system/classes/kohana/remote.php
Normal file
@@ -0,0 +1,152 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
/**
|
||||
* Provides remote server communications options using [curl](http://php.net/curl).
|
||||
*
|
||||
* @package Kohana
|
||||
* @category Helpers
|
||||
* @author Kohana Team
|
||||
* @copyright (c) 2008-2009 Kohana Team
|
||||
* @license http://kohanaphp.com/license
|
||||
*/
|
||||
class Kohana_Remote {
|
||||
|
||||
// Default curl options
|
||||
public static $default_options = array
|
||||
(
|
||||
CURLOPT_USERAGENT => 'Mozilla/5.0 (compatible; Kohana v3.0 +http://kohanaphp.com/)',
|
||||
CURLOPT_CONNECTTIMEOUT => 5,
|
||||
CURLOPT_TIMEOUT => 5,
|
||||
);
|
||||
|
||||
/**
|
||||
* Returns the output of a remote URL. Any [curl option](http://php.net/curl_setopt)
|
||||
* may be used.
|
||||
*
|
||||
* // Do a simple GET request
|
||||
* $data = Remote::get($url);
|
||||
*
|
||||
* // Do a POST request
|
||||
* $data = Remote::get($url, array(
|
||||
* CURLOPT_POST => TRUE,
|
||||
* CURLOPT_POSTFIELDS => http_build_query($array),
|
||||
* ));
|
||||
*
|
||||
* @param string remote URL
|
||||
* @param array curl options
|
||||
* @return string
|
||||
* @throws Kohana_Exception
|
||||
*/
|
||||
public static function get($url, array $options = NULL)
|
||||
{
|
||||
if ($options === NULL)
|
||||
{
|
||||
// Use default options
|
||||
$options = Remote::$default_options;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add default options
|
||||
$options = $options + Remote::$default_options;
|
||||
}
|
||||
|
||||
// The transfer must always be returned
|
||||
$options[CURLOPT_RETURNTRANSFER] = TRUE;
|
||||
|
||||
// Open a new remote connection
|
||||
$remote = curl_init($url);
|
||||
|
||||
// Set connection options
|
||||
if ( ! curl_setopt_array($remote, $options))
|
||||
{
|
||||
throw new Kohana_Exception('Failed to set CURL options, check CURL documentation: :url',
|
||||
array(':url' => 'http://php.net/curl_setopt_array'));
|
||||
}
|
||||
|
||||
// Get the response
|
||||
$response = curl_exec($remote);
|
||||
|
||||
// Get the response information
|
||||
$code = curl_getinfo($remote, CURLINFO_HTTP_CODE);
|
||||
|
||||
if ($code AND $code < 200 OR $code > 299)
|
||||
{
|
||||
$error = $response;
|
||||
}
|
||||
elseif ($response === FALSE)
|
||||
{
|
||||
$error = curl_error($remote);
|
||||
}
|
||||
|
||||
// Close the connection
|
||||
curl_close($remote);
|
||||
|
||||
if (isset($error))
|
||||
{
|
||||
throw new Kohana_Exception('Error fetching remote :url [ status :code ] :error',
|
||||
array(':url' => $url, ':code' => $code, ':error' => $error));
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the status code (200, 500, etc) for a URL.
|
||||
*
|
||||
* $status = Remote::status($url);
|
||||
*
|
||||
* @param string URL to check
|
||||
* @return integer
|
||||
*/
|
||||
public static function status($url)
|
||||
{
|
||||
// Get the hostname and path
|
||||
$url = parse_url($url);
|
||||
|
||||
if (empty($url['path']))
|
||||
{
|
||||
// Request the root document
|
||||
$url['path'] = '/';
|
||||
}
|
||||
|
||||
// Open a remote connection
|
||||
$port = isset($url['port']) ? $url['port'] : 80;
|
||||
$remote = fsockopen($url['host'], $port, $errno, $errstr, 5);
|
||||
|
||||
if ( ! is_resource($remote))
|
||||
return FALSE;
|
||||
|
||||
// Set CRLF
|
||||
$CRLF = "\r\n";
|
||||
|
||||
// Send request
|
||||
fwrite($remote, 'HEAD '.$url['path'].' HTTP/1.0'.$CRLF);
|
||||
fwrite($remote, 'Host: '.$url['host'].$CRLF);
|
||||
fwrite($remote, 'Connection: close'.$CRLF);
|
||||
fwrite($remote, 'User-Agent: Kohana Framework (+http://kohanaphp.com/)'.$CRLF);
|
||||
|
||||
// Send one more CRLF to terminate the headers
|
||||
fwrite($remote, $CRLF);
|
||||
|
||||
// Remote is offline
|
||||
$response = FALSE;
|
||||
|
||||
while ( ! feof($remote))
|
||||
{
|
||||
// Get the line
|
||||
$line = trim(fgets($remote, 512));
|
||||
|
||||
if ($line !== '' AND preg_match('#^HTTP/1\.[01] (\d{3})#', $line, $matches))
|
||||
{
|
||||
// Response code found
|
||||
$response = (int) $matches[1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Close the connection
|
||||
fclose($remote);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
} // End remote
|
1221
includes/kohana/system/classes/kohana/request.php
Normal file
1221
includes/kohana/system/classes/kohana/request.php
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,9 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
/**
|
||||
* @package Kohana
|
||||
* @category Exceptions
|
||||
* @author Kohana Team
|
||||
* @copyright (c) 2009 Kohana Team
|
||||
* @license http://kohanaphp.com/license
|
||||
*/
|
||||
class Kohana_Request_Exception extends Kohana_Exception { }
|
416
includes/kohana/system/classes/kohana/route.php
Normal file
416
includes/kohana/system/classes/kohana/route.php
Normal file
@@ -0,0 +1,416 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
/**
|
||||
* Routes are used to determine the controller and action for a requested URI.
|
||||
* Every route generates a regular expression which is used to match a URI
|
||||
* and a route. Routes may also contain keys which can be used to set the
|
||||
* controller, action, and parameters.
|
||||
*
|
||||
* Each <key> will be translated to a regular expression using a default
|
||||
* regular expression pattern. You can override the default pattern by providing
|
||||
* a pattern for the key:
|
||||
*
|
||||
* // This route will only match when <id> is a digit
|
||||
* Route::set('user', 'user/<action>/<id>', array('id' => '\d+'));
|
||||
*
|
||||
* // This route will match when <path> is anything
|
||||
* Route::set('file', '<path>', array('path' => '.*'));
|
||||
*
|
||||
* It is also possible to create optional segments by using parentheses in
|
||||
* the URI definition:
|
||||
*
|
||||
* // This is the standard default route, and no keys are required
|
||||
* Route::set('default', '(<controller>(/<action>(/<id>)))');
|
||||
*
|
||||
* // This route only requires the <file> key
|
||||
* Route::set('file', '(<path>/)<file>(.<format>)', array('path' => '.*', 'format' => '\w+'));
|
||||
*
|
||||
* Routes also provide a way to generate URIs (called "reverse routing"), which
|
||||
* makes them an extremely powerful and flexible way to generate internal links.
|
||||
*
|
||||
* @package Kohana
|
||||
* @category Base
|
||||
* @author Kohana Team
|
||||
* @copyright (c) 2008-2009 Kohana Team
|
||||
* @license http://kohanaphp.com/license
|
||||
*/
|
||||
class Kohana_Route {
|
||||
|
||||
// Defines the pattern of a <segment>
|
||||
const REGEX_KEY = '<([a-zA-Z0-9_]++)>';
|
||||
|
||||
// What can be part of a <segment> value
|
||||
const REGEX_SEGMENT = '[^/.,;?\n]++';
|
||||
|
||||
// What must be escaped in the route regex
|
||||
const REGEX_ESCAPE = '[.\\+*?[^\\]${}=!|]';
|
||||
|
||||
/**
|
||||
* @var string default action for all routes
|
||||
*/
|
||||
public static $default_action = 'index';
|
||||
|
||||
// List of route objects
|
||||
protected static $_routes = array();
|
||||
|
||||
/**
|
||||
* Stores a named route and returns it. The "action" will always be set to
|
||||
* "index" if it is not defined.
|
||||
*
|
||||
* Route::set('default', '(<controller>(/<action>(/<id>)))')
|
||||
* ->defaults(array(
|
||||
* 'controller' => 'welcome',
|
||||
* ));
|
||||
*
|
||||
* @param string route name
|
||||
* @param string URI pattern
|
||||
* @param array regex patterns for route keys
|
||||
* @return Route
|
||||
*/
|
||||
public static function set($name, $uri, array $regex = NULL)
|
||||
{
|
||||
return Route::$_routes[$name] = new Route($uri, $regex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a named route.
|
||||
*
|
||||
* $route = Route::get('default');
|
||||
*
|
||||
* @param string route name
|
||||
* @return Route
|
||||
* @throws Kohana_Exception
|
||||
*/
|
||||
public static function get($name)
|
||||
{
|
||||
if ( ! isset(Route::$_routes[$name]))
|
||||
{
|
||||
throw new Kohana_Exception('The requested route does not exist: :route',
|
||||
array(':route' => $name));
|
||||
}
|
||||
|
||||
return Route::$_routes[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all named routes.
|
||||
*
|
||||
* $routes = Route::all();
|
||||
*
|
||||
* @return array routes by name
|
||||
*/
|
||||
public static function all()
|
||||
{
|
||||
return Route::$_routes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of a route.
|
||||
*
|
||||
* $name = Route::name($route)
|
||||
*
|
||||
* @param object Route instance
|
||||
* @return string
|
||||
*/
|
||||
public static function name(Route $route)
|
||||
{
|
||||
return array_search($route, Route::$_routes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves or loads the route cache. If your routes will remain the same for
|
||||
* a long period of time, use this to reload the routes from the cache
|
||||
* rather than redefining them on every page load.
|
||||
*
|
||||
* if ( ! Route::cache())
|
||||
* {
|
||||
* // Set routes here
|
||||
* Route::cache(TRUE);
|
||||
* }
|
||||
*
|
||||
* @param boolean cache the current routes
|
||||
* @return void when saving routes
|
||||
* @return boolean when loading routes
|
||||
* @uses Kohana::cache
|
||||
*/
|
||||
public static function cache($save = FALSE)
|
||||
{
|
||||
if ($save === TRUE)
|
||||
{
|
||||
// Cache all defined routes
|
||||
Kohana::cache('Route::cache()', Route::$_routes);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($routes = Kohana::cache('Route::cache()'))
|
||||
{
|
||||
Route::$_routes = $routes;
|
||||
|
||||
// Routes were cached
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Routes were not cached
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a URL from a route name. This is a shortcut for:
|
||||
*
|
||||
* echo URL::site(Route::get($name)->uri($params), $protocol);
|
||||
*
|
||||
* @param string route name
|
||||
* @param array URI parameters
|
||||
* @param mixed protocol string or boolean, adds protocol and domain
|
||||
* @return string
|
||||
* @since 3.0.7
|
||||
* @uses URL::site
|
||||
*/
|
||||
public static function url($name, array $params = NULL, $protocol = NULL)
|
||||
{
|
||||
// Create a URI with the route and convert it to a URL
|
||||
return URL::site(Route::get($name)->uri($params), $protocol);
|
||||
}
|
||||
|
||||
// Route URI string
|
||||
protected $_uri = '';
|
||||
|
||||
// Regular expressions for route keys
|
||||
protected $_regex = array();
|
||||
|
||||
// Default values for route keys
|
||||
protected $_defaults = array('action' => 'index');
|
||||
|
||||
// Compiled regex cache
|
||||
protected $_route_regex;
|
||||
|
||||
/**
|
||||
* Creates a new route. Sets the URI and regular expressions for keys.
|
||||
* Routes should always be created with [Route::set] or they will not
|
||||
* be properly stored.
|
||||
*
|
||||
* $route = new Route($uri, $regex);
|
||||
*
|
||||
* @param string route URI pattern
|
||||
* @param array key patterns
|
||||
* @return void
|
||||
* @uses Route::_compile
|
||||
*/
|
||||
public function __construct($uri = NULL, array $regex = NULL)
|
||||
{
|
||||
if ($uri === NULL)
|
||||
{
|
||||
// Assume the route is from cache
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! empty($regex))
|
||||
{
|
||||
$this->_regex = $regex;
|
||||
}
|
||||
|
||||
// Store the URI that this route will match
|
||||
$this->_uri = $uri;
|
||||
|
||||
// Store the compiled regex locally
|
||||
$this->_route_regex = $this->_compile();
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides default values for keys when they are not present. The default
|
||||
* action will always be "index" unless it is overloaded here.
|
||||
*
|
||||
* $route->defaults(array(
|
||||
* 'controller' => 'welcome',
|
||||
* 'action' => 'index'
|
||||
* ));
|
||||
*
|
||||
* @param array key values
|
||||
* @return $this
|
||||
*/
|
||||
public function defaults(array $defaults = NULL)
|
||||
{
|
||||
$this->_defaults = $defaults;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if the route matches a given URI. A successful match will return
|
||||
* all of the routed parameters as an array. A failed match will return
|
||||
* boolean FALSE.
|
||||
*
|
||||
* // Params: controller = users, action = edit, id = 10
|
||||
* $params = $route->matches('users/edit/10');
|
||||
*
|
||||
* This method should almost always be used within an if/else block:
|
||||
*
|
||||
* if ($params = $route->matches($uri))
|
||||
* {
|
||||
* // Parse the parameters
|
||||
* }
|
||||
*
|
||||
* @param string URI to match
|
||||
* @return array on success
|
||||
* @return FALSE on failure
|
||||
*/
|
||||
public function matches($uri)
|
||||
{
|
||||
if ( ! preg_match($this->_route_regex, $uri, $matches))
|
||||
return FALSE;
|
||||
|
||||
$params = array();
|
||||
foreach ($matches as $key => $value)
|
||||
{
|
||||
if (is_int($key))
|
||||
{
|
||||
// Skip all unnamed keys
|
||||
continue;
|
||||
}
|
||||
|
||||
// Set the value for all matched keys
|
||||
$params[$key] = $value;
|
||||
}
|
||||
|
||||
foreach ($this->_defaults as $key => $value)
|
||||
{
|
||||
if ( ! isset($params[$key]) OR $params[$key] === '')
|
||||
{
|
||||
// Set default values for any key that was not matched
|
||||
$params[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a URI for the current route based on the parameters given.
|
||||
*
|
||||
* // Using the "default" route: "users/profile/10"
|
||||
* $route->uri(array(
|
||||
* 'controller' => 'users',
|
||||
* 'action' => 'profile',
|
||||
* 'id' => '10'
|
||||
* ));
|
||||
*
|
||||
* @param array URI parameters
|
||||
* @return string
|
||||
* @throws Kohana_Exception
|
||||
* @uses Route::REGEX_Key
|
||||
*/
|
||||
public function uri(array $params = NULL)
|
||||
{
|
||||
if ($params === NULL)
|
||||
{
|
||||
// Use the default parameters
|
||||
$params = $this->_defaults;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add the default parameters
|
||||
$params += $this->_defaults;
|
||||
}
|
||||
|
||||
// Start with the routed URI
|
||||
$uri = $this->_uri;
|
||||
|
||||
if (strpos($uri, '<') === FALSE AND strpos($uri, '(') === FALSE)
|
||||
{
|
||||
// This is a static route, no need to replace anything
|
||||
return $uri;
|
||||
}
|
||||
|
||||
while (preg_match('#\([^()]++\)#', $uri, $match))
|
||||
{
|
||||
// Search for the matched value
|
||||
$search = $match[0];
|
||||
|
||||
// Remove the parenthesis from the match as the replace
|
||||
$replace = substr($match[0], 1, -1);
|
||||
|
||||
while(preg_match('#'.Route::REGEX_KEY.'#', $replace, $match))
|
||||
{
|
||||
list($key, $param) = $match;
|
||||
|
||||
if (isset($params[$param]))
|
||||
{
|
||||
// Replace the key with the parameter value
|
||||
$replace = str_replace($key, $params[$param], $replace);
|
||||
}
|
||||
else
|
||||
{
|
||||
// This group has missing parameters
|
||||
$replace = '';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Replace the group in the URI
|
||||
$uri = str_replace($search, $replace, $uri);
|
||||
}
|
||||
|
||||
while(preg_match('#'.Route::REGEX_KEY.'#', $uri, $match))
|
||||
{
|
||||
list($key, $param) = $match;
|
||||
|
||||
if ( ! isset($params[$param]))
|
||||
{
|
||||
// Ungrouped parameters are required
|
||||
throw new Kohana_Exception('Required route parameter not passed: :param',
|
||||
array(':param' => $param));
|
||||
}
|
||||
|
||||
$uri = str_replace($key, $params[$param], $uri);
|
||||
}
|
||||
|
||||
// Trim all extra slashes from the URI
|
||||
$uri = preg_replace('#//+#', '/', rtrim($uri, '/'));
|
||||
|
||||
return $uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the compiled regular expression for the route. This translates
|
||||
* keys and optional groups to a proper PCRE regular expression.
|
||||
*
|
||||
* $regex = $route->_compile();
|
||||
*
|
||||
* @return string
|
||||
* @uses Route::REGEX_ESCAPE
|
||||
* @uses Route::REGEX_SEGMENT
|
||||
*/
|
||||
protected function _compile()
|
||||
{
|
||||
// The URI should be considered literal except for keys and optional parts
|
||||
// Escape everything preg_quote would escape except for : ( ) < >
|
||||
$regex = preg_replace('#'.Route::REGEX_ESCAPE.'#', '\\\\$0', $this->_uri);
|
||||
|
||||
if (strpos($regex, '(') !== FALSE)
|
||||
{
|
||||
// Make optional parts of the URI non-capturing and optional
|
||||
$regex = str_replace(array('(', ')'), array('(?:', ')?'), $regex);
|
||||
}
|
||||
|
||||
// Insert default regex for keys
|
||||
$regex = str_replace(array('<', '>'), array('(?P<', '>'.Route::REGEX_SEGMENT.')'), $regex);
|
||||
|
||||
if ( ! empty($this->_regex))
|
||||
{
|
||||
$search = $replace = array();
|
||||
foreach ($this->_regex as $key => $value)
|
||||
{
|
||||
$search[] = "<$key>".Route::REGEX_SEGMENT;
|
||||
$replace[] = "<$key>$value";
|
||||
}
|
||||
|
||||
// Replace the default regex with the user-specified regex
|
||||
$regex = str_replace($search, $replace, $regex);
|
||||
}
|
||||
|
||||
return '#^'.$regex.'$#uD';
|
||||
}
|
||||
|
||||
} // End Route
|
193
includes/kohana/system/classes/kohana/security.php
Normal file
193
includes/kohana/system/classes/kohana/security.php
Normal file
@@ -0,0 +1,193 @@
|
||||
<?php defined('SYSPATH') or die('No direct access allowed.');
|
||||
/**
|
||||
* Security helper class.
|
||||
*
|
||||
* @package Kohana
|
||||
* @category Security
|
||||
* @author Kohana Team
|
||||
* @copyright (c) 2007-2009 Kohana Team
|
||||
* @license http://kohanaphp.com/license
|
||||
*/
|
||||
class Kohana_Security {
|
||||
|
||||
/**
|
||||
* @var string key name used for token storage
|
||||
*/
|
||||
public static $token_name = 'security_token';
|
||||
|
||||
/**
|
||||
* Remove XSS from user input.
|
||||
*
|
||||
* $str = Security::xss_clean($str);
|
||||
*
|
||||
* @author Christian Stocker <chregu@bitflux.ch>
|
||||
* @copyright (c) 2001-2006 Bitflux GmbH
|
||||
* @param mixed string or array to sanitize
|
||||
* @return string
|
||||
* @deprecated since v3.0.5
|
||||
*/
|
||||
public static function xss_clean($str)
|
||||
{
|
||||
// http://svn.bitflux.ch/repos/public/popoon/trunk/classes/externalinput.php
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Copyright (c) 2001-2006 Bitflux GmbH |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||
// | you may not use this file except in compliance with the License. |
|
||||
// | You may obtain a copy of the License at |
|
||||
// | http://www.apache.org/licenses/LICENSE-2.0 |
|
||||
// | Unless required by applicable law or agreed to in writing, software |
|
||||
// | distributed under the License is distributed on an "AS IS" BASIS, |
|
||||
// | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
|
||||
// | implied. See the License for the specific language governing |
|
||||
// | permissions and limitations under the License. |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Author: Christian Stocker <chregu@bitflux.ch> |
|
||||
// +----------------------------------------------------------------------+
|
||||
//
|
||||
// Kohana Modifications:
|
||||
// * Changed double quotes to single quotes, changed indenting and spacing
|
||||
// * Removed magic_quotes stuff
|
||||
// * Increased regex readability:
|
||||
// * Used delimeters that aren't found in the pattern
|
||||
// * Removed all unneeded escapes
|
||||
// * Deleted U modifiers and swapped greediness where needed
|
||||
// * Increased regex speed:
|
||||
// * Made capturing parentheses non-capturing where possible
|
||||
// * Removed parentheses where possible
|
||||
// * Split up alternation alternatives
|
||||
// * Made some quantifiers possessive
|
||||
// * Handle arrays recursively
|
||||
|
||||
if (is_array($str) OR is_object($str))
|
||||
{
|
||||
foreach ($str as $k => $s)
|
||||
{
|
||||
$str[$k] = Security::xss_clean($s);
|
||||
}
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
// Remove all NULL bytes
|
||||
$str = str_replace("\0", '', $str);
|
||||
|
||||
// Fix &entity\n;
|
||||
$str = str_replace(array('&','<','>'), array('&amp;','&lt;','&gt;'), $str);
|
||||
$str = preg_replace('/(&#*\w+)[\x00-\x20]+;/u', '$1;', $str);
|
||||
$str = preg_replace('/(&#x*[0-9A-F]+);*/iu', '$1;', $str);
|
||||
$str = html_entity_decode($str, ENT_COMPAT, Kohana::$charset);
|
||||
|
||||
// Remove any attribute starting with "on" or xmlns
|
||||
$str = preg_replace('#(?:on[a-z]+|xmlns)\s*=\s*[\'"\x00-\x20]?[^\'>"]*[\'"\x00-\x20]?\s?#iu', '', $str);
|
||||
|
||||
// Remove javascript: and vbscript: protocols
|
||||
$str = preg_replace('#([a-z]*)[\x00-\x20]*=[\x00-\x20]*([`\'"]*)[\x00-\x20]*j[\x00-\x20]*a[\x00-\x20]*v[\x00-\x20]*a[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iu', '$1=$2nojavascript...', $str);
|
||||
$str = preg_replace('#([a-z]*)[\x00-\x20]*=([\'"]*)[\x00-\x20]*v[\x00-\x20]*b[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iu', '$1=$2novbscript...', $str);
|
||||
$str = preg_replace('#([a-z]*)[\x00-\x20]*=([\'"]*)[\x00-\x20]*-moz-binding[\x00-\x20]*:#u', '$1=$2nomozbinding...', $str);
|
||||
|
||||
// Only works in IE: <span style="width: expression(alert('Ping!'));"></span>
|
||||
$str = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?expression[\x00-\x20]*\([^>]*+>#is', '$1>', $str);
|
||||
$str = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?behaviour[\x00-\x20]*\([^>]*+>#is', '$1>', $str);
|
||||
$str = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:*[^>]*+>#ius', '$1>', $str);
|
||||
|
||||
// Remove namespaced elements (we do not need them)
|
||||
$str = preg_replace('#</*\w+:\w[^>]*+>#i', '', $str);
|
||||
|
||||
do
|
||||
{
|
||||
// Remove really unwanted tags
|
||||
$old = $str;
|
||||
$str = preg_replace('#</*(?:applet|b(?:ase|gsound|link)|embed|frame(?:set)?|i(?:frame|layer)|l(?:ayer|ink)|meta|object|s(?:cript|tyle)|title|xml)[^>]*+>#i', '', $str);
|
||||
}
|
||||
while ($old !== $str);
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate and store a unique token which can be used to help prevent
|
||||
* [CSRF](http://wikipedia.org/wiki/Cross_Site_Request_Forgery) attacks.
|
||||
*
|
||||
* $token = Security::token();
|
||||
*
|
||||
* You can insert this token into your forms as a hidden field:
|
||||
*
|
||||
* echo Form::hidden('csrf', Security::token());
|
||||
*
|
||||
* And then check it when using [Validate]:
|
||||
*
|
||||
* $array->rules('csrf', array(
|
||||
* 'not_empty' => NULL,
|
||||
* 'Security::check' => NULL,
|
||||
* ));
|
||||
*
|
||||
* This provides a basic, but effective, method of preventing CSRF attacks.
|
||||
*
|
||||
* @param boolean force a new token to be generated?
|
||||
* @return string
|
||||
* @uses Session::instance
|
||||
*/
|
||||
public static function token($new = FALSE)
|
||||
{
|
||||
$session = Session::instance();
|
||||
|
||||
// Get the current token
|
||||
$token = $session->get(Security::$token_name);
|
||||
|
||||
if ($new === TRUE OR ! $token)
|
||||
{
|
||||
// Generate a new unique token
|
||||
$token = uniqid('security');
|
||||
|
||||
// Store the new token
|
||||
$session->set(Security::$token_name, $token);
|
||||
}
|
||||
|
||||
return $token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that the given token matches the currently stored security token.
|
||||
*
|
||||
* if (Security::check($token))
|
||||
* {
|
||||
* // Pass
|
||||
* }
|
||||
*
|
||||
* @param string token to check
|
||||
* @return boolean
|
||||
* @uses Security::token
|
||||
*/
|
||||
public static function check($token)
|
||||
{
|
||||
return Security::token() === $token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove image tags from a string.
|
||||
*
|
||||
* $str = Security::strip_image_tags($str);
|
||||
*
|
||||
* @param string string to sanitize
|
||||
* @return string
|
||||
*/
|
||||
public static function strip_image_tags($str)
|
||||
{
|
||||
return preg_replace('#<img\s.*?(?:src\s*=\s*["\']?([^"\'<>\s]*)["\']?[^>]*)?>#is', '$1', $str);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes PHP tags in a string.
|
||||
*
|
||||
* $str = Security::encode_php_tags($str);
|
||||
*
|
||||
* @param string string to sanitize
|
||||
* @return string
|
||||
*/
|
||||
public static function encode_php_tags($str)
|
||||
{
|
||||
return str_replace(array('<?', '?>'), array('<?', '?>'), $str);
|
||||
}
|
||||
|
||||
} // End security
|
415
includes/kohana/system/classes/kohana/session.php
Normal file
415
includes/kohana/system/classes/kohana/session.php
Normal file
@@ -0,0 +1,415 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
/**
|
||||
* Base session class.
|
||||
*
|
||||
* @package Kohana
|
||||
* @category Session
|
||||
* @author Kohana Team
|
||||
* @copyright (c) 2008-2009 Kohana Team
|
||||
* @license http://kohanaphp.com/license
|
||||
*/
|
||||
abstract class Kohana_Session {
|
||||
|
||||
/**
|
||||
* @var string default session adapter
|
||||
*/
|
||||
public static $default = 'native';
|
||||
|
||||
// Session instances
|
||||
protected static $instances = array();
|
||||
|
||||
/**
|
||||
* Creates a singleton session of the given type. Some session types
|
||||
* (native, database) also support restarting a session by passing a
|
||||
* session id as the second parameter.
|
||||
*
|
||||
* $session = Session::instance();
|
||||
*
|
||||
* [!!] [Session::write] will automatically be called when the request ends.
|
||||
*
|
||||
* @param string type of session (native, cookie, etc)
|
||||
* @param string session identifier
|
||||
* @return Session
|
||||
* @uses Kohana::config
|
||||
*/
|
||||
public static function instance($type = NULL, $id = NULL)
|
||||
{
|
||||
if ($type === NULL)
|
||||
{
|
||||
// Use the default type
|
||||
$type = Session::$default;
|
||||
}
|
||||
|
||||
if ( ! isset(Session::$instances[$type]))
|
||||
{
|
||||
// Load the configuration for this type
|
||||
$config = Kohana::config('session')->get($type);
|
||||
|
||||
// Set the session class name
|
||||
$class = 'Session_'.ucfirst($type);
|
||||
|
||||
// Create a new session instance
|
||||
Session::$instances[$type] = $session = new $class($config, $id);
|
||||
|
||||
// Write the session at shutdown
|
||||
register_shutdown_function(array($session, 'write'));
|
||||
}
|
||||
|
||||
return Session::$instances[$type];
|
||||
}
|
||||
|
||||
// Cookie name
|
||||
protected $_name = 'session';
|
||||
|
||||
// Cookie lifetime
|
||||
protected $_lifetime = 0;
|
||||
|
||||
// Encrypt session data?
|
||||
protected $_encrypted = FALSE;
|
||||
|
||||
// Session data
|
||||
protected $_data = array();
|
||||
|
||||
// Is the session destroyed?
|
||||
protected $_destroyed = FALSE;
|
||||
|
||||
/**
|
||||
* Overloads the name, lifetime, and encrypted session settings.
|
||||
*
|
||||
* [!!] Sessions can only be created using the [Session::instance] method.
|
||||
*
|
||||
* @param array configuration
|
||||
* @param string session id
|
||||
* @return void
|
||||
* @uses Session::read
|
||||
*/
|
||||
public function __construct(array $config = NULL, $id = NULL)
|
||||
{
|
||||
if (isset($config['name']))
|
||||
{
|
||||
// Cookie name to store the session id in
|
||||
$this->_name = (string) $config['name'];
|
||||
}
|
||||
|
||||
if (isset($config['lifetime']))
|
||||
{
|
||||
// Cookie lifetime
|
||||
$this->_lifetime = (int) $config['lifetime'];
|
||||
}
|
||||
|
||||
if (isset($config['encrypted']))
|
||||
{
|
||||
if ($config['encrypted'] === TRUE)
|
||||
{
|
||||
// Use the default Encrypt instance
|
||||
$config['encrypted'] = 'default';
|
||||
}
|
||||
|
||||
// Enable or disable encryption of data
|
||||
$this->_encrypted = $config['encrypted'];
|
||||
}
|
||||
|
||||
// Load the session
|
||||
$this->read($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Session object is rendered to a serialized string. If encryption is
|
||||
* enabled, the session will be encrypted. If not, the output string will
|
||||
* be encoded using [base64_encode].
|
||||
*
|
||||
* echo $session;
|
||||
*
|
||||
* @return string
|
||||
* @uses Encrypt::encode
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
// Serialize the data array
|
||||
$data = serialize($this->_data);
|
||||
|
||||
if ($this->_encrypted)
|
||||
{
|
||||
// Encrypt the data using the default key
|
||||
$data = Encrypt::instance($this->_encrypted)->encode($data);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Obfuscate the data with base64 encoding
|
||||
$data = base64_encode($data);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current session array. The returned array can also be
|
||||
* assigned by reference.
|
||||
*
|
||||
* // Get a copy of the current session data
|
||||
* $data = $session->as_array();
|
||||
*
|
||||
* // Assign by reference for modification
|
||||
* $data =& $session->as_array();
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function & as_array()
|
||||
{
|
||||
return $this->_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current session id, if the session supports it.
|
||||
*
|
||||
* $id = $session->id();
|
||||
*
|
||||
* [!!] Not all session types have ids.
|
||||
*
|
||||
* @return string
|
||||
* @since 3.0.8
|
||||
*/
|
||||
public function id()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current session cookie name.
|
||||
*
|
||||
* $name = $session->id();
|
||||
*
|
||||
* @return string
|
||||
* @since 3.0.8
|
||||
*/
|
||||
public function name()
|
||||
{
|
||||
return $this->_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a variable from the session array.
|
||||
*
|
||||
* $foo = $session->get('foo');
|
||||
*
|
||||
* @param string variable name
|
||||
* @param mixed default value to return
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($key, $default = NULL)
|
||||
{
|
||||
return array_key_exists($key, $this->_data) ? $this->_data[$key] : $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get and delete a variable from the session array.
|
||||
*
|
||||
* $bar = $session->get_once('bar');
|
||||
*
|
||||
* @param string variable name
|
||||
* @param mixed default value to return
|
||||
* @return mixed
|
||||
*/
|
||||
public function get_once($key, $default = NULL)
|
||||
{
|
||||
$value = $this->get($key, $default);
|
||||
|
||||
unset($this->_data[$key]);
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a variable in the session array.
|
||||
*
|
||||
* $session->set('foo', 'bar');
|
||||
*
|
||||
* @param string variable name
|
||||
* @param mixed value
|
||||
* @return $this
|
||||
*/
|
||||
public function set($key, $value)
|
||||
{
|
||||
$this->_data[$key] = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a variable by reference.
|
||||
*
|
||||
* $session->bind('foo', $foo);
|
||||
*
|
||||
* @param string variable name
|
||||
* @param mixed referenced value
|
||||
* @return $this
|
||||
*/
|
||||
public function bind($key, & $value)
|
||||
{
|
||||
$this->_data[$key] =& $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a variable in the session array.
|
||||
*
|
||||
* $session->delete('foo');
|
||||
*
|
||||
* @param string variable name
|
||||
* @param ...
|
||||
* @return $this
|
||||
*/
|
||||
public function delete($key)
|
||||
{
|
||||
$args = func_get_args();
|
||||
|
||||
foreach ($args as $key)
|
||||
{
|
||||
unset($this->_data[$key]);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads existing session data.
|
||||
*
|
||||
* $session->read();
|
||||
*
|
||||
* @param string session id
|
||||
* @return void
|
||||
*/
|
||||
public function read($id = NULL)
|
||||
{
|
||||
if (is_string($data = $this->_read($id)))
|
||||
{
|
||||
try
|
||||
{
|
||||
if ($this->_encrypted)
|
||||
{
|
||||
// Decrypt the data using the default key
|
||||
$data = Encrypt::instance($this->_encrypted)->decode($data);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Decode the base64 encoded data
|
||||
$data = base64_decode($data);
|
||||
}
|
||||
|
||||
// Unserialize the data
|
||||
$data = unserialize($data);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
// Ignore all reading errors
|
||||
}
|
||||
}
|
||||
|
||||
if (is_array($data))
|
||||
{
|
||||
// Load the data locally
|
||||
$this->_data = $data;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a new session id and returns it.
|
||||
*
|
||||
* $id = $session->regenerate();
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function regenerate()
|
||||
{
|
||||
return $this->_regenerate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the last_active timestamp and saves the session.
|
||||
*
|
||||
* $session->write();
|
||||
*
|
||||
* [!!] Any errors that occur during session writing will be logged,
|
||||
* but not displayed, because sessions are written after output has
|
||||
* been sent.
|
||||
*
|
||||
* @return boolean
|
||||
* @uses Kohana::$log
|
||||
*/
|
||||
public function write()
|
||||
{
|
||||
if (headers_sent() OR $this->_destroyed)
|
||||
{
|
||||
// Session cannot be written when the headers are sent or when
|
||||
// the session has been destroyed
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Set the last active timestamp
|
||||
$this->_data['last_active'] = time();
|
||||
|
||||
try
|
||||
{
|
||||
return $this->_write();
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
// Log & ignore all errors when a write fails
|
||||
Kohana::$log->add(Kohana::ERROR, Kohana::exception_text($e))->write();
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Completely destroy the current session.
|
||||
*
|
||||
* $success = $session->destroy();
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function destroy()
|
||||
{
|
||||
if ($this->_destroyed === FALSE)
|
||||
{
|
||||
if ($this->_destroyed = $this->_destroy())
|
||||
{
|
||||
// The session has been destroyed, clear all data
|
||||
$this->_data = array();
|
||||
}
|
||||
}
|
||||
|
||||
return $this->_destroyed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the raw session data string and returns it.
|
||||
*
|
||||
* @param string session id
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function _read($id = NULL);
|
||||
|
||||
/**
|
||||
* Generate a new session id and return it.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function _regenerate();
|
||||
|
||||
/**
|
||||
* Writes the current session.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
abstract protected function _write();
|
||||
|
||||
/**
|
||||
* Destroys the current session.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
abstract protected function _destroy();
|
||||
|
||||
} // End Session
|
34
includes/kohana/system/classes/kohana/session/cookie.php
Normal file
34
includes/kohana/system/classes/kohana/session/cookie.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
/**
|
||||
* Cookie-based session class.
|
||||
*
|
||||
* @package Kohana
|
||||
* @category Session
|
||||
* @author Kohana Team
|
||||
* @copyright (c) 2008-2009 Kohana Team
|
||||
* @license http://kohanaphp.com/license
|
||||
*/
|
||||
class Kohana_Session_Cookie extends Session {
|
||||
|
||||
protected function _read($id = NULL)
|
||||
{
|
||||
return Cookie::get($this->_name, NULL);
|
||||
}
|
||||
|
||||
protected function _regenerate()
|
||||
{
|
||||
// Cookie sessions have no id
|
||||
return NULL;
|
||||
}
|
||||
|
||||
protected function _write()
|
||||
{
|
||||
return Cookie::set($this->_name, $this->__toString(), $this->_lifetime);
|
||||
}
|
||||
|
||||
protected function _destroy()
|
||||
{
|
||||
return Cookie::delete($this->_name);
|
||||
}
|
||||
|
||||
} // End Session_Cookie
|
68
includes/kohana/system/classes/kohana/session/native.php
Normal file
68
includes/kohana/system/classes/kohana/session/native.php
Normal file
@@ -0,0 +1,68 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
/**
|
||||
* Native PHP session class.
|
||||
*
|
||||
* @package Kohana
|
||||
* @category Session
|
||||
* @author Kohana Team
|
||||
* @copyright (c) 2008-2009 Kohana Team
|
||||
* @license http://kohanaphp.com/license
|
||||
*/
|
||||
class Kohana_Session_Native extends Session {
|
||||
|
||||
public function id()
|
||||
{
|
||||
return session_id();
|
||||
}
|
||||
|
||||
protected function _read($id = NULL)
|
||||
{
|
||||
// Sync up the session cookie with Cookie parameters
|
||||
session_set_cookie_params($this->_lifetime, Cookie::$path, Cookie::$domain, Cookie::$secure, Cookie::$httponly);
|
||||
|
||||
// Do not allow PHP to send Cache-Control headers
|
||||
session_cache_limiter(FALSE);
|
||||
|
||||
// Set the session cookie name
|
||||
session_name($this->_name);
|
||||
|
||||
if ($id)
|
||||
{
|
||||
// Set the session id
|
||||
session_id($id);
|
||||
}
|
||||
|
||||
// Start the session
|
||||
session_start();
|
||||
|
||||
// Use the $_SESSION global for storing data
|
||||
$this->_data =& $_SESSION;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
protected function _regenerate()
|
||||
{
|
||||
// Regenerate the session id
|
||||
session_regenerate_id();
|
||||
|
||||
return session_id();
|
||||
}
|
||||
|
||||
protected function _write()
|
||||
{
|
||||
// Write and close the session
|
||||
session_write_close();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
protected function _destroy()
|
||||
{
|
||||
// Destroy the current session
|
||||
session_destroy();
|
||||
|
||||
return ! session_id();
|
||||
}
|
||||
|
||||
} // End Session_Native
|
590
includes/kohana/system/classes/kohana/text.php
Normal file
590
includes/kohana/system/classes/kohana/text.php
Normal file
@@ -0,0 +1,590 @@
|
||||
<?php defined('SYSPATH') or die('No direct access allowed.');
|
||||
/**
|
||||
* Text helper class. Provides simple methods for working with text.
|
||||
*
|
||||
* @package Kohana
|
||||
* @category Helpers
|
||||
* @author Kohana Team
|
||||
* @copyright (c) 2007-2008 Kohana Team
|
||||
* @license http://kohanaphp.com/license
|
||||
*/
|
||||
class Kohana_Text {
|
||||
|
||||
/**
|
||||
* @var array number units and text equivalents
|
||||
*/
|
||||
public static $units = array(
|
||||
1000000000 => 'billion',
|
||||
1000000 => 'million',
|
||||
1000 => 'thousand',
|
||||
100 => 'hundred',
|
||||
90 => 'ninety',
|
||||
80 => 'eighty',
|
||||
70 => 'seventy',
|
||||
60 => 'sixty',
|
||||
50 => 'fifty',
|
||||
40 => 'fourty',
|
||||
30 => 'thirty',
|
||||
20 => 'twenty',
|
||||
19 => 'nineteen',
|
||||
18 => 'eighteen',
|
||||
17 => 'seventeen',
|
||||
16 => 'sixteen',
|
||||
15 => 'fifteen',
|
||||
14 => 'fourteen',
|
||||
13 => 'thirteen',
|
||||
12 => 'twelve',
|
||||
11 => 'eleven',
|
||||
10 => 'ten',
|
||||
9 => 'nine',
|
||||
8 => 'eight',
|
||||
7 => 'seven',
|
||||
6 => 'six',
|
||||
5 => 'five',
|
||||
4 => 'four',
|
||||
3 => 'three',
|
||||
2 => 'two',
|
||||
1 => 'one',
|
||||
);
|
||||
|
||||
/**
|
||||
* Limits a phrase to a given number of words.
|
||||
*
|
||||
* $text = Text::limit_words($text);
|
||||
*
|
||||
* @param string phrase to limit words of
|
||||
* @param integer number of words to limit to
|
||||
* @param string end character or entity
|
||||
* @return string
|
||||
*/
|
||||
public static function limit_words($str, $limit = 100, $end_char = NULL)
|
||||
{
|
||||
$limit = (int) $limit;
|
||||
$end_char = ($end_char === NULL) ? '…' : $end_char;
|
||||
|
||||
if (trim($str) === '')
|
||||
return $str;
|
||||
|
||||
if ($limit <= 0)
|
||||
return $end_char;
|
||||
|
||||
preg_match('/^\s*+(?:\S++\s*+){1,'.$limit.'}/u', $str, $matches);
|
||||
|
||||
// Only attach the end character if the matched string is shorter
|
||||
// than the starting string.
|
||||
return rtrim($matches[0]).(strlen($matches[0]) === strlen($str) ? '' : $end_char);
|
||||
}
|
||||
|
||||
/**
|
||||
* Limits a phrase to a given number of characters.
|
||||
*
|
||||
* $text = Text::limit_chars($text);
|
||||
*
|
||||
* @param string phrase to limit characters of
|
||||
* @param integer number of characters to limit to
|
||||
* @param string end character or entity
|
||||
* @param boolean enable or disable the preservation of words while limiting
|
||||
* @return string
|
||||
* @uses UTF8::strlen
|
||||
*/
|
||||
public static function limit_chars($str, $limit = 100, $end_char = NULL, $preserve_words = FALSE)
|
||||
{
|
||||
$end_char = ($end_char === NULL) ? '…' : $end_char;
|
||||
|
||||
$limit = (int) $limit;
|
||||
|
||||
if (trim($str) === '' OR UTF8::strlen($str) <= $limit)
|
||||
return $str;
|
||||
|
||||
if ($limit <= 0)
|
||||
return $end_char;
|
||||
|
||||
if ($preserve_words === FALSE)
|
||||
return rtrim(UTF8::substr($str, 0, $limit)).$end_char;
|
||||
|
||||
// Don't preserve words. The limit is considered the top limit.
|
||||
// No strings with a length longer than $limit should be returned.
|
||||
if ( ! preg_match('/^.{0,'.$limit.'}\s/us', $str, $matches))
|
||||
return $end_char;
|
||||
|
||||
return rtrim($matches[0]).(strlen($matches[0]) === strlen($str) ? '' : $end_char);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alternates between two or more strings.
|
||||
*
|
||||
* echo Text::alternate('one', 'two'); // "one"
|
||||
* echo Text::alternate('one', 'two'); // "two"
|
||||
* echo Text::alternate('one', 'two'); // "one"
|
||||
*
|
||||
* Note that using multiple iterations of different strings may produce
|
||||
* unexpected results.
|
||||
*
|
||||
* @param string strings to alternate between
|
||||
* @return string
|
||||
*/
|
||||
public static function alternate()
|
||||
{
|
||||
static $i;
|
||||
|
||||
if (func_num_args() === 0)
|
||||
{
|
||||
$i = 0;
|
||||
return '';
|
||||
}
|
||||
|
||||
$args = func_get_args();
|
||||
return $args[($i++ % count($args))];
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a random string of a given type and length.
|
||||
*
|
||||
*
|
||||
* $str = Text::random(); // 8 character random string
|
||||
*
|
||||
* The following types are supported:
|
||||
*
|
||||
* alnum
|
||||
* : Upper and lower case a-z, 0-9 (default)
|
||||
*
|
||||
* alpha
|
||||
* : Upper and lower case a-z
|
||||
*
|
||||
* hexdec
|
||||
* : Hexadecimal characters a-f, 0-9
|
||||
*
|
||||
* distinct
|
||||
* : Uppercase characters and numbers that cannot be confused
|
||||
*
|
||||
* You can also create a custom type by providing the "pool" of characters
|
||||
* as the type.
|
||||
*
|
||||
* @param string a type of pool, or a string of characters to use as the pool
|
||||
* @param integer length of string to return
|
||||
* @return string
|
||||
* @uses UTF8::split
|
||||
*/
|
||||
public static function random($type = NULL, $length = 8)
|
||||
{
|
||||
if ($type === NULL)
|
||||
{
|
||||
// Default is to generate an alphanumeric string
|
||||
$type = 'alnum';
|
||||
}
|
||||
|
||||
$utf8 = FALSE;
|
||||
|
||||
switch ($type)
|
||||
{
|
||||
case 'alnum':
|
||||
$pool = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||
break;
|
||||
case 'alpha':
|
||||
$pool = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||
break;
|
||||
case 'hexdec':
|
||||
$pool = '0123456789abcdef';
|
||||
break;
|
||||
case 'numeric':
|
||||
$pool = '0123456789';
|
||||
break;
|
||||
case 'nozero':
|
||||
$pool = '123456789';
|
||||
break;
|
||||
case 'distinct':
|
||||
$pool = '2345679ACDEFHJKLMNPRSTUVWXYZ';
|
||||
break;
|
||||
default:
|
||||
$pool = (string) $type;
|
||||
$utf8 = ! UTF8::is_ascii($pool);
|
||||
break;
|
||||
}
|
||||
|
||||
// Split the pool into an array of characters
|
||||
$pool = ($utf8 === TRUE) ? UTF8::str_split($pool, 1) : str_split($pool, 1);
|
||||
|
||||
// Largest pool key
|
||||
$max = count($pool) - 1;
|
||||
|
||||
$str = '';
|
||||
for ($i = 0; $i < $length; $i++)
|
||||
{
|
||||
// Select a random character from the pool and add it to the string
|
||||
$str .= $pool[mt_rand(0, $max)];
|
||||
}
|
||||
|
||||
// Make sure alnum strings contain at least one letter and one digit
|
||||
if ($type === 'alnum' AND $length > 1)
|
||||
{
|
||||
if (ctype_alpha($str))
|
||||
{
|
||||
// Add a random digit
|
||||
$str[mt_rand(0, $length - 1)] = chr(mt_rand(48, 57));
|
||||
}
|
||||
elseif (ctype_digit($str))
|
||||
{
|
||||
// Add a random letter
|
||||
$str[mt_rand(0, $length - 1)] = chr(mt_rand(65, 90));
|
||||
}
|
||||
}
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduces multiple slashes in a string to single slashes.
|
||||
*
|
||||
* $str = Text::reduce_slashes('foo//bar/baz'); // "foo/bar/baz"
|
||||
*
|
||||
* @param string string to reduce slashes of
|
||||
* @return string
|
||||
*/
|
||||
public static function reduce_slashes($str)
|
||||
{
|
||||
return preg_replace('#(?<!:)//+#', '/', $str);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the given words with a string.
|
||||
*
|
||||
* // Displays "What the #####, man!"
|
||||
* echo Text::censor('What the frick, man!', array(
|
||||
* 'frick' => '#####',
|
||||
* ));
|
||||
*
|
||||
* @param string phrase to replace words in
|
||||
* @param array words to replace
|
||||
* @param string replacement string
|
||||
* @param boolean replace words across word boundries (space, period, etc)
|
||||
* @return string
|
||||
* @uses UTF8::strlen
|
||||
*/
|
||||
public static function censor($str, $badwords, $replacement = '#', $replace_partial_words = TRUE)
|
||||
{
|
||||
foreach ((array) $badwords as $key => $badword)
|
||||
{
|
||||
$badwords[$key] = str_replace('\*', '\S*?', preg_quote((string) $badword));
|
||||
}
|
||||
|
||||
$regex = '('.implode('|', $badwords).')';
|
||||
|
||||
if ($replace_partial_words === FALSE)
|
||||
{
|
||||
// Just using \b isn't sufficient when we need to replace a badword that already contains word boundaries itself
|
||||
$regex = '(?<=\b|\s|^)'.$regex.'(?=\b|\s|$)';
|
||||
}
|
||||
|
||||
$regex = '!'.$regex.'!ui';
|
||||
|
||||
if (UTF8::strlen($replacement) == 1)
|
||||
{
|
||||
$regex .= 'e';
|
||||
return preg_replace($regex, 'str_repeat($replacement, UTF8::strlen(\'$1\'))', $str);
|
||||
}
|
||||
|
||||
return preg_replace($regex, $replacement, $str);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the text that is similar between a set of words.
|
||||
*
|
||||
* $match = Text::similar(array('fred', 'fran', 'free'); // "fr"
|
||||
*
|
||||
* @param array words to find similar text of
|
||||
* @return string
|
||||
*/
|
||||
public static function similar(array $words)
|
||||
{
|
||||
// First word is the word to match against
|
||||
$word = current($words);
|
||||
|
||||
for ($i = 0, $max = strlen($word); $i < $max; ++$i)
|
||||
{
|
||||
foreach ($words as $w)
|
||||
{
|
||||
// Once a difference is found, break out of the loops
|
||||
if ( ! isset($w[$i]) OR $w[$i] !== $word[$i])
|
||||
break 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Return the similar text
|
||||
return substr($word, 0, $i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts text email addresses and anchors into links. Existing links
|
||||
* will not be altered.
|
||||
*
|
||||
* echo Text::auto_link($text);
|
||||
*
|
||||
* [!!] This method is not foolproof since it uses regex to parse HTML.
|
||||
*
|
||||
* @param string text to auto link
|
||||
* @return string
|
||||
* @uses Text::auto_link_urls
|
||||
* @uses Text::auto_link_emails
|
||||
*/
|
||||
public static function auto_link($text)
|
||||
{
|
||||
// Auto link emails first to prevent problems with "www.domain.com@example.com"
|
||||
return Text::auto_link_urls(Text::auto_link_emails($text));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts text anchors into links. Existing links will not be altered.
|
||||
*
|
||||
* echo Text::auto_link_urls($text);
|
||||
*
|
||||
* [!!] This method is not foolproof since it uses regex to parse HTML.
|
||||
*
|
||||
* @param string text to auto link
|
||||
* @return string
|
||||
* @uses HTML::anchor
|
||||
*/
|
||||
public static function auto_link_urls($text)
|
||||
{
|
||||
// Find and replace all http/https/ftp/ftps links that are not part of an existing html anchor
|
||||
$text = preg_replace_callback('~\b(?<!href="|">)(?:ht|f)tps?://\S+(?:/|\b)~i', 'Text::_auto_link_urls_callback1', $text);
|
||||
|
||||
// Find and replace all naked www.links.com (without http://)
|
||||
return preg_replace_callback('~\b(?<!://|">)www(?:\.[a-z0-9][-a-z0-9]*+)+\.[a-z]{2,6}\b~i', 'Text::_auto_link_urls_callback2', $text);
|
||||
}
|
||||
|
||||
protected static function _auto_link_urls_callback1($matches)
|
||||
{
|
||||
return HTML::anchor($matches[0]);
|
||||
}
|
||||
|
||||
protected static function _auto_link_urls_callback2($matches)
|
||||
{
|
||||
return HTML::anchor('http://'.$matches[0], $matches[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts text email addresses into links. Existing links will not
|
||||
* be altered.
|
||||
*
|
||||
* echo Text::auto_link_emails($text);
|
||||
*
|
||||
* [!!] This method is not foolproof since it uses regex to parse HTML.
|
||||
*
|
||||
* @param string text to auto link
|
||||
* @return string
|
||||
* @uses HTML::mailto
|
||||
*/
|
||||
public static function auto_link_emails($text)
|
||||
{
|
||||
// Find and replace all email addresses that are not part of an existing html mailto anchor
|
||||
// Note: The "58;" negative lookbehind prevents matching of existing encoded html mailto anchors
|
||||
// The html entity for a colon (:) is : or : or : etc.
|
||||
return preg_replace_callback('~\b(?<!href="mailto:|58;)(?!\.)[-+_a-z0-9.]++(?<!\.)@(?![-.])[-a-z0-9.]+(?<!\.)\.[a-z]{2,6}\b(?!</a>)~i', 'Text::_auto_link_emails_callback', $text);
|
||||
}
|
||||
|
||||
protected static function _auto_link_emails_callback($matches)
|
||||
{
|
||||
return HTML::mailto($matches[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Automatically applies "p" and "br" markup to text.
|
||||
* Basically [nl2br](http://php.net/nl2br) on steroids.
|
||||
*
|
||||
* echo Text::auto_p($text);
|
||||
*
|
||||
* [!!] This method is not foolproof since it uses regex to parse HTML.
|
||||
*
|
||||
* @param string subject
|
||||
* @param boolean convert single linebreaks to <br />
|
||||
* @return string
|
||||
*/
|
||||
public static function auto_p($str, $br = TRUE)
|
||||
{
|
||||
// Trim whitespace
|
||||
if (($str = trim($str)) === '')
|
||||
return '';
|
||||
|
||||
// Standardize newlines
|
||||
$str = str_replace(array("\r\n", "\r"), "\n", $str);
|
||||
|
||||
// Trim whitespace on each line
|
||||
$str = preg_replace('~^[ \t]+~m', '', $str);
|
||||
$str = preg_replace('~[ \t]+$~m', '', $str);
|
||||
|
||||
// The following regexes only need to be executed if the string contains html
|
||||
if ($html_found = (strpos($str, '<') !== FALSE))
|
||||
{
|
||||
// Elements that should not be surrounded by p tags
|
||||
$no_p = '(?:p|div|h[1-6r]|ul|ol|li|blockquote|d[dlt]|pre|t[dhr]|t(?:able|body|foot|head)|c(?:aption|olgroup)|form|s(?:elect|tyle)|a(?:ddress|rea)|ma(?:p|th))';
|
||||
|
||||
// Put at least two linebreaks before and after $no_p elements
|
||||
$str = preg_replace('~^<'.$no_p.'[^>]*+>~im', "\n$0", $str);
|
||||
$str = preg_replace('~</'.$no_p.'\s*+>$~im', "$0\n", $str);
|
||||
}
|
||||
|
||||
// Do the <p> magic!
|
||||
$str = '<p>'.trim($str).'</p>';
|
||||
$str = preg_replace('~\n{2,}~', "</p>\n\n<p>", $str);
|
||||
|
||||
// The following regexes only need to be executed if the string contains html
|
||||
if ($html_found !== FALSE)
|
||||
{
|
||||
// Remove p tags around $no_p elements
|
||||
$str = preg_replace('~<p>(?=</?'.$no_p.'[^>]*+>)~i', '', $str);
|
||||
$str = preg_replace('~(</?'.$no_p.'[^>]*+>)</p>~i', '$1', $str);
|
||||
}
|
||||
|
||||
// Convert single linebreaks to <br />
|
||||
if ($br === TRUE)
|
||||
{
|
||||
$str = preg_replace('~(?<!\n)\n(?!\n)~', "<br />\n", $str);
|
||||
}
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns human readable sizes. Based on original functions written by
|
||||
* [Aidan Lister](http://aidanlister.com/repos/v/function.size_readable.php)
|
||||
* and [Quentin Zervaas](http://www.phpriot.com/d/code/strings/filesize-format/).
|
||||
*
|
||||
* echo Text::bytes(filesize($file));
|
||||
*
|
||||
* @param integer size in bytes
|
||||
* @param string a definitive unit
|
||||
* @param string the return string format
|
||||
* @param boolean whether to use SI prefixes or IEC
|
||||
* @return string
|
||||
*/
|
||||
public static function bytes($bytes, $force_unit = NULL, $format = NULL, $si = TRUE)
|
||||
{
|
||||
// Format string
|
||||
$format = ($format === NULL) ? '%01.2f %s' : (string) $format;
|
||||
|
||||
// IEC prefixes (binary)
|
||||
if ($si == FALSE OR strpos($force_unit, 'i') !== FALSE)
|
||||
{
|
||||
$units = array('B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB');
|
||||
$mod = 1024;
|
||||
}
|
||||
// SI prefixes (decimal)
|
||||
else
|
||||
{
|
||||
$units = array('B', 'kB', 'MB', 'GB', 'TB', 'PB');
|
||||
$mod = 1000;
|
||||
}
|
||||
|
||||
// Determine unit to use
|
||||
if (($power = array_search((string) $force_unit, $units)) === FALSE)
|
||||
{
|
||||
$power = ($bytes > 0) ? floor(log($bytes, $mod)) : 0;
|
||||
}
|
||||
|
||||
return sprintf($format, $bytes / pow($mod, $power), $units[$power]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a number to human-readable text.
|
||||
*
|
||||
* // Display: one thousand and twenty-four
|
||||
* echo Text::number(1024);
|
||||
*
|
||||
* // Display: five million, six hundred and thirty-two
|
||||
* echo Text::number(5000632);
|
||||
*
|
||||
* @param integer number to format
|
||||
* @return string
|
||||
* @since 3.0.8
|
||||
*/
|
||||
public static function number($number)
|
||||
{
|
||||
// The number must always be an integer
|
||||
$number = (int) $number;
|
||||
|
||||
// Uncompiled text version
|
||||
$text = array();
|
||||
|
||||
// Last matched unit within the loop
|
||||
$last_unit = NULL;
|
||||
|
||||
// The last matched item within the loop
|
||||
$last_item = '';
|
||||
|
||||
foreach (Text::$units as $unit => $name)
|
||||
{
|
||||
if ($number / $unit >= 1)
|
||||
{
|
||||
// $value = the number of times the number is divisble by unit
|
||||
$number -= $unit * ($value = (int) floor($number / $unit));
|
||||
// Temporary var for textifying the current unit
|
||||
$item = '';
|
||||
|
||||
if ($unit < 100)
|
||||
{
|
||||
if ($last_unit < 100 AND $last_unit >= 20)
|
||||
{
|
||||
$last_item .= '-'.$name;
|
||||
}
|
||||
else
|
||||
{
|
||||
$item = $name;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$item = Text::number($value).' '.$name;
|
||||
}
|
||||
|
||||
// In the situation that we need to make a composite number (i.e. twenty-three)
|
||||
// then we need to modify the previous entry
|
||||
if(empty($item))
|
||||
{
|
||||
array_pop($text);
|
||||
|
||||
$item = $last_item;
|
||||
}
|
||||
|
||||
$last_item = $text[] = $item;
|
||||
$last_unit = $unit;
|
||||
}
|
||||
}
|
||||
|
||||
if(count($text) > 1)
|
||||
{
|
||||
$and = array_pop($text);
|
||||
}
|
||||
|
||||
$text = implode(', ', $text);
|
||||
|
||||
if(isset($and))
|
||||
{
|
||||
$text .= ' and '.$and;
|
||||
}
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevents [widow words](http://www.shauninman.com/archive/2006/08/22/widont_wordpress_plugin)
|
||||
* by inserting a non-breaking space between the last two words.
|
||||
*
|
||||
* echo Text::widont($text);
|
||||
*
|
||||
* @param string text to remove widows from
|
||||
* @return string
|
||||
*/
|
||||
public static function widont($str)
|
||||
{
|
||||
$str = rtrim($str);
|
||||
$space = strrpos($str, ' ');
|
||||
|
||||
if ($space !== FALSE)
|
||||
{
|
||||
$str = substr($str, 0, $space).' '.substr($str, $space + 1);
|
||||
}
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
} // End text
|
205
includes/kohana/system/classes/kohana/upload.php
Normal file
205
includes/kohana/system/classes/kohana/upload.php
Normal file
@@ -0,0 +1,205 @@
|
||||
<?php defined('SYSPATH') or die('No direct access allowed.');
|
||||
/**
|
||||
* Upload helper class for working with uploaded files and [Validate].
|
||||
*
|
||||
* $array = Validate::factory($_FILES);
|
||||
*
|
||||
* [!!] Remember to define your form with "enctype=multipart/form-data" or file
|
||||
* uploading will not work!
|
||||
*
|
||||
* The following configuration properties can be set:
|
||||
*
|
||||
* - [Upload::$remove_spaces]
|
||||
* - [Upload::$default_directory]
|
||||
*
|
||||
* @package Kohana
|
||||
* @category Helpers
|
||||
* @author Kohana Team
|
||||
* @copyright (c) 2007-2009 Kohana Team
|
||||
* @license http://kohanaphp.com/license
|
||||
*/
|
||||
class Kohana_Upload {
|
||||
|
||||
/**
|
||||
* @var boolean remove spaces in uploaded files
|
||||
*/
|
||||
public static $remove_spaces = TRUE;
|
||||
|
||||
/**
|
||||
* @var string default upload directory
|
||||
*/
|
||||
public static $default_directory = 'upload';
|
||||
|
||||
/**
|
||||
* Save an uploaded file to a new location. If no filename is provided,
|
||||
* the original filename will be used, with a unique prefix added.
|
||||
*
|
||||
* This method should be used after validating the $_FILES array:
|
||||
*
|
||||
* if ($array->check())
|
||||
* {
|
||||
* // Upload is valid, save it
|
||||
* Upload::save($_FILES['file']);
|
||||
* }
|
||||
*
|
||||
* @param array uploaded file data
|
||||
* @param string new filename
|
||||
* @param string new directory
|
||||
* @param integer chmod mask
|
||||
* @return string on success, full path to new file
|
||||
* @return FALSE on failure
|
||||
*/
|
||||
public static function save(array $file, $filename = NULL, $directory = NULL, $chmod = 0644)
|
||||
{
|
||||
if ( ! isset($file['tmp_name']) OR ! is_uploaded_file($file['tmp_name']))
|
||||
{
|
||||
// Ignore corrupted uploads
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ($filename === NULL)
|
||||
{
|
||||
// Use the default filename, with a timestamp pre-pended
|
||||
$filename = uniqid().$file['name'];
|
||||
}
|
||||
|
||||
if (Upload::$remove_spaces === TRUE)
|
||||
{
|
||||
// Remove spaces from the filename
|
||||
$filename = preg_replace('/\s+/', '_', $filename);
|
||||
}
|
||||
|
||||
if ($directory === NULL)
|
||||
{
|
||||
// Use the pre-configured upload directory
|
||||
$directory = Upload::$default_directory;
|
||||
}
|
||||
|
||||
if ( ! is_dir($directory) OR ! is_writable(realpath($directory)))
|
||||
{
|
||||
throw new Kohana_Exception('Directory :dir must be writable',
|
||||
array(':dir' => Kohana::debug_path($directory)));
|
||||
}
|
||||
|
||||
// Make the filename into a complete path
|
||||
$filename = realpath($directory).DIRECTORY_SEPARATOR.$filename;
|
||||
|
||||
if (move_uploaded_file($file['tmp_name'], $filename))
|
||||
{
|
||||
if ($chmod !== FALSE)
|
||||
{
|
||||
// Set permissions on filename
|
||||
chmod($filename, $chmod);
|
||||
}
|
||||
|
||||
// Return new file path
|
||||
return $filename;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if upload data is valid, even if no file was uploaded. If you
|
||||
* _do_ require a file to be uploaded, add the [Upload::not_empty] rule
|
||||
* before this rule.
|
||||
*
|
||||
* $array->rule('file', 'Upload::valid')
|
||||
*
|
||||
* @param array $_FILES item
|
||||
* @return bool
|
||||
*/
|
||||
public static function valid($file)
|
||||
{
|
||||
return (isset($file['error'])
|
||||
AND isset($file['name'])
|
||||
AND isset($file['type'])
|
||||
AND isset($file['tmp_name'])
|
||||
AND isset($file['size']));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if a successful upload has been made.
|
||||
*
|
||||
* $array->rule('file', 'Upload::not_empty');
|
||||
*
|
||||
* @param array $_FILES item
|
||||
* @return bool
|
||||
*/
|
||||
public static function not_empty(array $file)
|
||||
{
|
||||
return (isset($file['error'])
|
||||
AND isset($file['tmp_name'])
|
||||
AND $file['error'] === UPLOAD_ERR_OK
|
||||
AND is_uploaded_file($file['tmp_name'])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if an uploaded file is an allowed file type, by extension.
|
||||
*
|
||||
* $array->rule('file', 'Upload::type', array(array('jpg', 'png', 'gif')));
|
||||
*
|
||||
* @param array $_FILES item
|
||||
* @param array allowed file extensions
|
||||
* @return bool
|
||||
*/
|
||||
public static function type(array $file, array $allowed)
|
||||
{
|
||||
if ($file['error'] !== UPLOAD_ERR_OK)
|
||||
return TRUE;
|
||||
|
||||
$ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
|
||||
|
||||
return in_array($ext, $allowed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validation rule to test if an uploaded file is allowed by file size.
|
||||
* File sizes are defined as: SB, where S is the size (1, 15, 300, etc) and
|
||||
* B is the byte modifier: (B)ytes, (K)ilobytes, (M)egabytes, (G)igabytes.
|
||||
*
|
||||
* $array->rule('file', 'Upload::size', array('1M'))
|
||||
*
|
||||
* @param array $_FILES item
|
||||
* @param string maximum file size
|
||||
* @return bool
|
||||
*/
|
||||
public static function size(array $file, $size)
|
||||
{
|
||||
if ($file['error'] === UPLOAD_ERR_INI_SIZE)
|
||||
{
|
||||
// Upload is larger than PHP allowed size
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ($file['error'] !== UPLOAD_ERR_OK)
|
||||
{
|
||||
// The upload failed, no size to check
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Only one size is allowed
|
||||
$size = strtoupper(trim($size));
|
||||
|
||||
if ( ! preg_match('/^[0-9]++[BKMG]$/', $size))
|
||||
{
|
||||
throw new Kohana_Exception('Size does not contain a digit and a byte value: :size', array(
|
||||
':size' => $size,
|
||||
));
|
||||
}
|
||||
|
||||
// Make the size into a power of 1024
|
||||
switch (substr($size, -1))
|
||||
{
|
||||
case 'G': $size = intval($size) * pow(1024, 3); break;
|
||||
case 'M': $size = intval($size) * pow(1024, 2); break;
|
||||
case 'K': $size = intval($size) * pow(1024, 1); break;
|
||||
default: $size = intval($size); break;
|
||||
}
|
||||
|
||||
// Test that the file is under or equal to the max size
|
||||
return ($file['size'] <= $size);
|
||||
}
|
||||
|
||||
} // End upload
|
175
includes/kohana/system/classes/kohana/url.php
Normal file
175
includes/kohana/system/classes/kohana/url.php
Normal file
@@ -0,0 +1,175 @@
|
||||
<?php defined('SYSPATH') or die('No direct access allowed.');
|
||||
/**
|
||||
* URL helper class.
|
||||
*
|
||||
* @package Kohana
|
||||
* @category Helpers
|
||||
* @author Kohana Team
|
||||
* @copyright (c) 2007-2009 Kohana Team
|
||||
* @license http://kohanaphp.com/license
|
||||
*/
|
||||
class Kohana_URL {
|
||||
|
||||
/**
|
||||
* Gets the base URL to the application. To include the current protocol,
|
||||
* use TRUE. To specify a protocol, provide the protocol as a string.
|
||||
* If a protocol is used, a complete URL will be generated using the
|
||||
* `$_SERVER['HTTP_HOST']` variable.
|
||||
*
|
||||
* // Absolute relative, no host or protocol
|
||||
* echo URL::base();
|
||||
*
|
||||
* // Complete relative, with host and protocol
|
||||
* echo URL::base(TRUE, TRUE);
|
||||
*
|
||||
* // Complete relative, with host and "https" protocol
|
||||
* echo URL::base(TRUE, 'https');
|
||||
*
|
||||
* @param boolean add index file to URL?
|
||||
* @param mixed protocol string or boolean, add protocol and domain?
|
||||
* @return string
|
||||
* @uses Kohana::$index_file
|
||||
* @uses Request::$protocol
|
||||
*/
|
||||
public static function base($index = FALSE, $protocol = FALSE)
|
||||
{
|
||||
// Start with the configured base URL
|
||||
$base_url = Kohana::$base_url;
|
||||
|
||||
if ($protocol === TRUE)
|
||||
{
|
||||
// Use the current protocol
|
||||
$protocol = Request::$protocol;
|
||||
}
|
||||
elseif ($protocol === FALSE AND $scheme = parse_url($base_url, PHP_URL_SCHEME))
|
||||
{
|
||||
// Use the configured default protocol
|
||||
$protocol = $scheme;
|
||||
}
|
||||
|
||||
if ($index === TRUE AND ! empty(Kohana::$index_file))
|
||||
{
|
||||
// Add the index file to the URL
|
||||
$base_url .= Kohana::$index_file.'/';
|
||||
}
|
||||
|
||||
if (is_string($protocol))
|
||||
{
|
||||
if ($domain = parse_url($base_url, PHP_URL_HOST))
|
||||
{
|
||||
// Remove everything but the path from the URL
|
||||
$base_url = parse_url($base_url, PHP_URL_PATH);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Attempt ot use HTPP_HOST and fallback to SERVER_NAME
|
||||
$domain = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME'];
|
||||
}
|
||||
|
||||
// Add the protocol and domain to the base URL
|
||||
$base_url = $protocol.'://'.$domain.$base_url;
|
||||
}
|
||||
|
||||
return $base_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches an absolute site URL based on a URI segment.
|
||||
*
|
||||
* echo URL::site('foo/bar');
|
||||
*
|
||||
* @param string site URI to convert
|
||||
* @param mixed protocol string or boolean, add protocol and domain?
|
||||
* @return string
|
||||
* @uses URL::base
|
||||
*/
|
||||
public static function site($uri = '', $protocol = FALSE)
|
||||
{
|
||||
// Chop off possible scheme, host, port, user and pass parts
|
||||
$path = preg_replace('~^[-a-z0-9+.]++://[^/]++/?~', '', trim($uri, '/'));
|
||||
|
||||
if ( ! UTF8::is_ascii($path))
|
||||
{
|
||||
// Encode all non-ASCII characters, as per RFC 1738
|
||||
$path = preg_replace('~([^/]+)~e', 'rawurlencode("$1")', $path);
|
||||
}
|
||||
|
||||
// Concat the URL
|
||||
return URL::base(TRUE, $protocol).$path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges the current GET parameters with an array of new or overloaded
|
||||
* parameters and returns the resulting query string.
|
||||
*
|
||||
* // Returns "?sort=title&limit=10" combined with any existing GET values
|
||||
* $query = URL::query(array('sort' => 'title', 'limit' => 10));
|
||||
*
|
||||
* Typically you would use this when you are sorting query results,
|
||||
* or something similar.
|
||||
*
|
||||
* [!!] Parameters with a NULL value are left out.
|
||||
*
|
||||
* @param array array of GET parameters
|
||||
* @return string
|
||||
*/
|
||||
public static function query(array $params = NULL)
|
||||
{
|
||||
if ($params === NULL)
|
||||
{
|
||||
// Use only the current parameters
|
||||
$params = $_GET;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Merge the current and new parameters
|
||||
$params = array_merge($_GET, $params);
|
||||
}
|
||||
|
||||
if (empty($params))
|
||||
{
|
||||
// No query parameters
|
||||
return '';
|
||||
}
|
||||
|
||||
$query = http_build_query($params, '', '&');
|
||||
|
||||
// Don't prepend '?' to an empty string
|
||||
return ($query === '') ? '' : '?'.$query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a phrase to a URL-safe title.
|
||||
*
|
||||
* echo URL::title('My Blog Post'); // "my-blog-post"
|
||||
*
|
||||
* @param string phrase to convert
|
||||
* @param string word separator (any single character)
|
||||
* @param boolean transliterate to ASCII?
|
||||
* @return string
|
||||
* @uses UTF8::transliterate_to_ascii
|
||||
*/
|
||||
public static function title($title, $separator = '-', $ascii_only = FALSE)
|
||||
{
|
||||
if ($ascii_only === TRUE)
|
||||
{
|
||||
// Transliterate non-ASCII characters
|
||||
$title = UTF8::transliterate_to_ascii($title);
|
||||
|
||||
// Remove all characters that are not the separator, a-z, 0-9, or whitespace
|
||||
$title = preg_replace('![^'.preg_quote($separator).'a-z0-9\s]+!', '', strtolower($title));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Remove all characters that are not the separator, letters, numbers, or whitespace
|
||||
$title = preg_replace('![^'.preg_quote($separator).'\pL\pN\s]+!u', '', UTF8::strtolower($title));
|
||||
}
|
||||
|
||||
// Replace all separator characters and whitespace by a single separator
|
||||
$title = preg_replace('!['.preg_quote($separator).'\s]+!u', $separator, $title);
|
||||
|
||||
// Trim separators from the beginning and end
|
||||
return trim($title, $separator);
|
||||
}
|
||||
|
||||
} // End url
|
761
includes/kohana/system/classes/kohana/utf8.php
Normal file
761
includes/kohana/system/classes/kohana/utf8.php
Normal file
@@ -0,0 +1,761 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
/**
|
||||
* A port of [phputf8](http://phputf8.sourceforge.net/) to a unified set
|
||||
* of files. Provides multi-byte aware replacement string functions.
|
||||
*
|
||||
* For UTF-8 support to work correctly, the following requirements must be met:
|
||||
*
|
||||
* - PCRE needs to be compiled with UTF-8 support (--enable-utf8)
|
||||
* - Support for [Unicode properties](http://php.net/manual/reference.pcre.pattern.modifiers.php)
|
||||
* is highly recommended (--enable-unicode-properties)
|
||||
* - UTF-8 conversion will be much more reliable if the
|
||||
* [iconv extension](http://php.net/iconv) is loaded
|
||||
* - The [mbstring extension](http://php.net/mbstring) is highly recommended,
|
||||
* but must not be overloading string functions
|
||||
*
|
||||
* [!!] This file is licensed differently from the rest of Kohana. As a port of
|
||||
* [phputf8](http://phputf8.sourceforge.net/), this file is released under the LGPL.
|
||||
*
|
||||
* @package Kohana
|
||||
* @category Base
|
||||
* @author Kohana Team
|
||||
* @copyright (c) 2007-2008 Kohana Team
|
||||
* @copyright (c) 2005 Harry Fuecks
|
||||
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt
|
||||
*/
|
||||
class Kohana_UTF8 {
|
||||
|
||||
/**
|
||||
* @var boolean does the server support UTF-8 natively?
|
||||
*/
|
||||
public static $server_utf8 = NULL;
|
||||
|
||||
/**
|
||||
* @var array list of called methods
|
||||
*/
|
||||
public static $called = array();
|
||||
|
||||
/**
|
||||
* Recursively cleans arrays, objects, and strings. Removes ASCII control
|
||||
* codes and converts to the requested charset while silently discarding
|
||||
* incompatible characters.
|
||||
*
|
||||
* UTF8::clean($_GET); // Clean GET data
|
||||
*
|
||||
* [!!] This method requires [Iconv](http://php.net/iconv)
|
||||
*
|
||||
* @param mixed variable to clean
|
||||
* @param string character set, defaults to UTF-8
|
||||
* @return mixed
|
||||
* @uses UTF8::strip_ascii_ctrl
|
||||
* @uses UTF8::is_ascii
|
||||
*/
|
||||
public static function clean($var, $charset = 'UTF-8')
|
||||
{
|
||||
if (is_array($var) OR is_object($var))
|
||||
{
|
||||
foreach ($var as $key => $val)
|
||||
{
|
||||
// Recursion!
|
||||
$var[self::clean($key)] = self::clean($val);
|
||||
}
|
||||
}
|
||||
elseif (is_string($var) AND $var !== '')
|
||||
{
|
||||
// Remove control characters
|
||||
$var = self::strip_ascii_ctrl($var);
|
||||
|
||||
if ( ! self::is_ascii($var))
|
||||
{
|
||||
// Disable notices
|
||||
$ER = error_reporting(~E_NOTICE);
|
||||
|
||||
// iconv is expensive, so it is only used when needed
|
||||
$var = iconv($charset, $charset.'//IGNORE', $var);
|
||||
|
||||
// Turn notices back on
|
||||
error_reporting($ER);
|
||||
}
|
||||
}
|
||||
|
||||
return $var;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether a string contains only 7-bit ASCII bytes. This is used to
|
||||
* determine when to use native functions or UTF-8 functions.
|
||||
*
|
||||
* $ascii = UTF8::is_ascii($str);
|
||||
*
|
||||
* @param mixed string or array of strings to check
|
||||
* @return boolean
|
||||
*/
|
||||
public static function is_ascii($str)
|
||||
{
|
||||
if (is_array($str))
|
||||
{
|
||||
$str = implode($str);
|
||||
}
|
||||
|
||||
return ! preg_match('/[^\x00-\x7F]/S', $str);
|
||||
}
|
||||
|
||||
/**
|
||||
* Strips out device control codes in the ASCII range.
|
||||
*
|
||||
* $str = UTF8::strip_ascii_ctrl($str);
|
||||
*
|
||||
* @param string string to clean
|
||||
* @return string
|
||||
*/
|
||||
public static function strip_ascii_ctrl($str)
|
||||
{
|
||||
return preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]+/S', '', $str);
|
||||
}
|
||||
|
||||
/**
|
||||
* Strips out all non-7bit ASCII bytes.
|
||||
*
|
||||
* $str = UTF8::strip_non_ascii($str);
|
||||
*
|
||||
* @param string string to clean
|
||||
* @return string
|
||||
*/
|
||||
public static function strip_non_ascii($str)
|
||||
{
|
||||
return preg_replace('/[^\x00-\x7F]+/S', '', $str);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces special/accented UTF-8 characters by ASCII-7 "equivalents".
|
||||
*
|
||||
* $ascii = UTF8::transliterate_to_ascii($utf8);
|
||||
*
|
||||
* @author Andreas Gohr <andi@splitbrain.org>
|
||||
* @param string string to transliterate
|
||||
* @param integer -1 lowercase only, +1 uppercase only, 0 both cases
|
||||
* @return string
|
||||
*/
|
||||
public static function transliterate_to_ascii($str, $case = 0)
|
||||
{
|
||||
if ( ! isset(self::$called[__FUNCTION__]))
|
||||
{
|
||||
require SYSPATH.'utf8'.DIRECTORY_SEPARATOR.__FUNCTION__.EXT;
|
||||
|
||||
// Function has been called
|
||||
self::$called[__FUNCTION__] = TRUE;
|
||||
}
|
||||
|
||||
return _transliterate_to_ascii($str, $case);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length of the given string. This is a UTF8-aware version
|
||||
* of [strlen](http://php.net/strlen).
|
||||
*
|
||||
* $length = UTF8::strlen($str);
|
||||
*
|
||||
* @param string string being measured for length
|
||||
* @return integer
|
||||
* @uses UTF8::$server_utf8
|
||||
*/
|
||||
public static function strlen($str)
|
||||
{
|
||||
if (UTF8::$server_utf8)
|
||||
return mb_strlen($str, Kohana::$charset);
|
||||
|
||||
if ( ! isset(self::$called[__FUNCTION__]))
|
||||
{
|
||||
require SYSPATH.'utf8'.DIRECTORY_SEPARATOR.__FUNCTION__.EXT;
|
||||
|
||||
// Function has been called
|
||||
self::$called[__FUNCTION__] = TRUE;
|
||||
}
|
||||
|
||||
return _strlen($str);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds position of first occurrence of a UTF-8 string. This is a
|
||||
* UTF8-aware version of [strpos](http://php.net/strpos).
|
||||
*
|
||||
* $position = UTF8::strpos($str, $search);
|
||||
*
|
||||
* @author Harry Fuecks <hfuecks@gmail.com>
|
||||
* @param string haystack
|
||||
* @param string needle
|
||||
* @param integer offset from which character in haystack to start searching
|
||||
* @return integer position of needle
|
||||
* @return boolean FALSE if the needle is not found
|
||||
* @uses UTF8::$server_utf8
|
||||
*/
|
||||
public static function strpos($str, $search, $offset = 0)
|
||||
{
|
||||
if (UTF8::$server_utf8)
|
||||
return mb_strpos($str, $search, $offset, Kohana::$charset);
|
||||
|
||||
if ( ! isset(self::$called[__FUNCTION__]))
|
||||
{
|
||||
require SYSPATH.'utf8'.DIRECTORY_SEPARATOR.__FUNCTION__.EXT;
|
||||
|
||||
// Function has been called
|
||||
self::$called[__FUNCTION__] = TRUE;
|
||||
}
|
||||
|
||||
return _strpos($str, $search, $offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds position of last occurrence of a char in a UTF-8 string. This is
|
||||
* a UTF8-aware version of [strrpos](http://php.net/strrpos).
|
||||
*
|
||||
* $position = UTF8::strrpos($str, $search);
|
||||
*
|
||||
* @author Harry Fuecks <hfuecks@gmail.com>
|
||||
* @param string haystack
|
||||
* @param string needle
|
||||
* @param integer offset from which character in haystack to start searching
|
||||
* @return integer position of needle
|
||||
* @return boolean FALSE if the needle is not found
|
||||
* @uses UTF8::$server_utf8
|
||||
*/
|
||||
public static function strrpos($str, $search, $offset = 0)
|
||||
{
|
||||
if (UTF8::$server_utf8)
|
||||
return mb_strrpos($str, $search, $offset, Kohana::$charset);
|
||||
|
||||
if ( ! isset(self::$called[__FUNCTION__]))
|
||||
{
|
||||
require SYSPATH.'utf8'.DIRECTORY_SEPARATOR.__FUNCTION__.EXT;
|
||||
|
||||
// Function has been called
|
||||
self::$called[__FUNCTION__] = TRUE;
|
||||
}
|
||||
|
||||
return _strrpos($str, $search, $offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns part of a UTF-8 string. This is a UTF8-aware version
|
||||
* of [substr](http://php.net/substr).
|
||||
*
|
||||
* $sub = UTF8::substr($str, $offset);
|
||||
*
|
||||
* @author Chris Smith <chris@jalakai.co.uk>
|
||||
* @param string input string
|
||||
* @param integer offset
|
||||
* @param integer length limit
|
||||
* @return string
|
||||
* @uses UTF8::$server_utf8
|
||||
* @uses Kohana::$charset
|
||||
*/
|
||||
public static function substr($str, $offset, $length = NULL)
|
||||
{
|
||||
if (UTF8::$server_utf8)
|
||||
return ($length === NULL)
|
||||
? mb_substr($str, $offset, mb_strlen($str), Kohana::$charset)
|
||||
: mb_substr($str, $offset, $length, Kohana::$charset);
|
||||
|
||||
if ( ! isset(self::$called[__FUNCTION__]))
|
||||
{
|
||||
require SYSPATH.'utf8'.DIRECTORY_SEPARATOR.__FUNCTION__.EXT;
|
||||
|
||||
// Function has been called
|
||||
self::$called[__FUNCTION__] = TRUE;
|
||||
}
|
||||
|
||||
return _substr($str, $offset, $length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces text within a portion of a UTF-8 string. This is a UTF8-aware
|
||||
* version of [substr_replace](http://php.net/substr_replace).
|
||||
*
|
||||
* $str = UTF8::substr_replace($str, $replacement, $offset);
|
||||
*
|
||||
* @author Harry Fuecks <hfuecks@gmail.com>
|
||||
* @param string input string
|
||||
* @param string replacement string
|
||||
* @param integer offset
|
||||
* @return string
|
||||
*/
|
||||
public static function substr_replace($str, $replacement, $offset, $length = NULL)
|
||||
{
|
||||
if ( ! isset(self::$called[__FUNCTION__]))
|
||||
{
|
||||
require SYSPATH.'utf8'.DIRECTORY_SEPARATOR.__FUNCTION__.EXT;
|
||||
|
||||
// Function has been called
|
||||
self::$called[__FUNCTION__] = TRUE;
|
||||
}
|
||||
|
||||
return _substr_replace($str, $replacement, $offset, $length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a UTF-8 string lowercase. This is a UTF8-aware version
|
||||
* of [strtolower](http://php.net/strtolower).
|
||||
*
|
||||
* $str = UTF8::strtolower($str);
|
||||
*
|
||||
* @author Andreas Gohr <andi@splitbrain.org>
|
||||
* @param string mixed case string
|
||||
* @return string
|
||||
* @uses UTF8::$server_utf8
|
||||
*/
|
||||
public static function strtolower($str)
|
||||
{
|
||||
if (UTF8::$server_utf8)
|
||||
return mb_strtolower($str, Kohana::$charset);
|
||||
|
||||
if ( ! isset(self::$called[__FUNCTION__]))
|
||||
{
|
||||
require SYSPATH.'utf8'.DIRECTORY_SEPARATOR.__FUNCTION__.EXT;
|
||||
|
||||
// Function has been called
|
||||
self::$called[__FUNCTION__] = TRUE;
|
||||
}
|
||||
|
||||
return _strtolower($str);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a UTF-8 string uppercase. This is a UTF8-aware version
|
||||
* of [strtoupper](http://php.net/strtoupper).
|
||||
*
|
||||
* @author Andreas Gohr <andi@splitbrain.org>
|
||||
* @param string mixed case string
|
||||
* @return string
|
||||
* @uses UTF8::$server_utf8
|
||||
* @uses Kohana::$charset
|
||||
*/
|
||||
public static function strtoupper($str)
|
||||
{
|
||||
if (UTF8::$server_utf8)
|
||||
return mb_strtoupper($str, Kohana::$charset);
|
||||
|
||||
if ( ! isset(self::$called[__FUNCTION__]))
|
||||
{
|
||||
require SYSPATH.'utf8'.DIRECTORY_SEPARATOR.__FUNCTION__.EXT;
|
||||
|
||||
// Function has been called
|
||||
self::$called[__FUNCTION__] = TRUE;
|
||||
}
|
||||
|
||||
return _strtoupper($str);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a UTF-8 string's first character uppercase. This is a UTF8-aware
|
||||
* version of [ucfirst](http://php.net/ucfirst).
|
||||
*
|
||||
* $str = UTF8::ucfirst($str);
|
||||
*
|
||||
* @author Harry Fuecks <hfuecks@gmail.com>
|
||||
* @param string mixed case string
|
||||
* @return string
|
||||
*/
|
||||
public static function ucfirst($str)
|
||||
{
|
||||
if ( ! isset(self::$called[__FUNCTION__]))
|
||||
{
|
||||
require SYSPATH.'utf8'.DIRECTORY_SEPARATOR.__FUNCTION__.EXT;
|
||||
|
||||
// Function has been called
|
||||
self::$called[__FUNCTION__] = TRUE;
|
||||
}
|
||||
|
||||
return _ucfirst($str);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes the first character of every word in a UTF-8 string uppercase.
|
||||
* This is a UTF8-aware version of [ucwords](http://php.net/ucwords).
|
||||
*
|
||||
* $str = UTF8::ucwords($str);
|
||||
*
|
||||
* @author Harry Fuecks <hfuecks@gmail.com>
|
||||
* @param string mixed case string
|
||||
* @return string
|
||||
* @uses UTF8::$server_utf8
|
||||
*/
|
||||
public static function ucwords($str)
|
||||
{
|
||||
if ( ! isset(self::$called[__FUNCTION__]))
|
||||
{
|
||||
require SYSPATH.'utf8'.DIRECTORY_SEPARATOR.__FUNCTION__.EXT;
|
||||
|
||||
// Function has been called
|
||||
self::$called[__FUNCTION__] = TRUE;
|
||||
}
|
||||
|
||||
return _ucwords($str);
|
||||
}
|
||||
|
||||
/**
|
||||
* Case-insensitive UTF-8 string comparison. This is a UTF8-aware version
|
||||
* of [strcasecmp](http://php.net/strcasecmp).
|
||||
*
|
||||
* $compare = UTF8::strcasecmp($str1, $str2);
|
||||
*
|
||||
* @author Harry Fuecks <hfuecks@gmail.com>
|
||||
* @param string string to compare
|
||||
* @param string string to compare
|
||||
* @return integer less than 0 if str1 is less than str2
|
||||
* @return integer greater than 0 if str1 is greater than str2
|
||||
* @return integer 0 if they are equal
|
||||
*/
|
||||
public static function strcasecmp($str1, $str2)
|
||||
{
|
||||
if ( ! isset(self::$called[__FUNCTION__]))
|
||||
{
|
||||
require SYSPATH.'utf8'.DIRECTORY_SEPARATOR.__FUNCTION__.EXT;
|
||||
|
||||
// Function has been called
|
||||
self::$called[__FUNCTION__] = TRUE;
|
||||
}
|
||||
|
||||
return _strcasecmp($str1, $str2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string or an array with all occurrences of search in subject
|
||||
* (ignoring case) and replaced with the given replace value. This is a
|
||||
* UTF8-aware version of [str_ireplace](http://php.net/str_ireplace).
|
||||
*
|
||||
* [!!] This function is very slow compared to the native version. Avoid
|
||||
* using it when possible.
|
||||
*
|
||||
* @author Harry Fuecks <hfuecks@gmail.com
|
||||
* @param string|array text to replace
|
||||
* @param string|array replacement text
|
||||
* @param string|array subject text
|
||||
* @param integer number of matched and replaced needles will be returned via this parameter which is passed by reference
|
||||
* @return string if the input was a string
|
||||
* @return array if the input was an array
|
||||
*/
|
||||
public static function str_ireplace($search, $replace, $str, & $count = NULL)
|
||||
{
|
||||
if ( ! isset(self::$called[__FUNCTION__]))
|
||||
{
|
||||
require SYSPATH.'utf8'.DIRECTORY_SEPARATOR.__FUNCTION__.EXT;
|
||||
|
||||
// Function has been called
|
||||
self::$called[__FUNCTION__] = TRUE;
|
||||
}
|
||||
|
||||
return _str_ireplace($search, $replace, $str, $count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Case-insenstive UTF-8 version of strstr. Returns all of input string
|
||||
* from the first occurrence of needle to the end. This is a UTF8-aware
|
||||
* version of [stristr](http://php.net/stristr).
|
||||
*
|
||||
* $found = UTF8::stristr($str, $search);
|
||||
*
|
||||
* @author Harry Fuecks <hfuecks@gmail.com>
|
||||
* @param string input string
|
||||
* @param string needle
|
||||
* @return string matched substring if found
|
||||
* @return FALSE if the substring was not found
|
||||
*/
|
||||
public static function stristr($str, $search)
|
||||
{
|
||||
if ( ! isset(self::$called[__FUNCTION__]))
|
||||
{
|
||||
require SYSPATH.'utf8'.DIRECTORY_SEPARATOR.__FUNCTION__.EXT;
|
||||
|
||||
// Function has been called
|
||||
self::$called[__FUNCTION__] = TRUE;
|
||||
}
|
||||
|
||||
return _stristr($str, $search);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the length of the initial segment matching mask. This is a
|
||||
* UTF8-aware version of [strspn](http://php.net/strspn).
|
||||
*
|
||||
* $found = UTF8::strspn($str, $mask);
|
||||
*
|
||||
* @author Harry Fuecks <hfuecks@gmail.com>
|
||||
* @param string input string
|
||||
* @param string mask for search
|
||||
* @param integer start position of the string to examine
|
||||
* @param integer length of the string to examine
|
||||
* @return integer length of the initial segment that contains characters in the mask
|
||||
*/
|
||||
public static function strspn($str, $mask, $offset = NULL, $length = NULL)
|
||||
{
|
||||
if ( ! isset(self::$called[__FUNCTION__]))
|
||||
{
|
||||
require SYSPATH.'utf8'.DIRECTORY_SEPARATOR.__FUNCTION__.EXT;
|
||||
|
||||
// Function has been called
|
||||
self::$called[__FUNCTION__] = TRUE;
|
||||
}
|
||||
|
||||
return _strspn($str, $mask, $offset, $length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the length of the initial segment not matching mask. This is a
|
||||
* UTF8-aware version of [strcspn](http://php.net/strcspn).
|
||||
*
|
||||
* $found = UTF8::strcspn($str, $mask);
|
||||
*
|
||||
* @author Harry Fuecks <hfuecks@gmail.com>
|
||||
* @param string input string
|
||||
* @param string mask for search
|
||||
* @param integer start position of the string to examine
|
||||
* @param integer length of the string to examine
|
||||
* @return integer length of the initial segment that contains characters not in the mask
|
||||
*/
|
||||
public static function strcspn($str, $mask, $offset = NULL, $length = NULL)
|
||||
{
|
||||
if ( ! isset(self::$called[__FUNCTION__]))
|
||||
{
|
||||
require SYSPATH.'utf8'.DIRECTORY_SEPARATOR.__FUNCTION__.EXT;
|
||||
|
||||
// Function has been called
|
||||
self::$called[__FUNCTION__] = TRUE;
|
||||
}
|
||||
|
||||
return _strcspn($str, $mask, $offset, $length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pads a UTF-8 string to a certain length with another string. This is a
|
||||
* UTF8-aware version of [str_pad](http://php.net/str_pad).
|
||||
*
|
||||
* $str = UTF8::str_pad($str, $length);
|
||||
*
|
||||
* @author Harry Fuecks <hfuecks@gmail.com>
|
||||
* @param string input string
|
||||
* @param integer desired string length after padding
|
||||
* @param string string to use as padding
|
||||
* @param string padding type: STR_PAD_RIGHT, STR_PAD_LEFT, or STR_PAD_BOTH
|
||||
* @return string
|
||||
*/
|
||||
public static function str_pad($str, $final_str_length, $pad_str = ' ', $pad_type = STR_PAD_RIGHT)
|
||||
{
|
||||
if ( ! isset(self::$called[__FUNCTION__]))
|
||||
{
|
||||
require SYSPATH.'utf8'.DIRECTORY_SEPARATOR.__FUNCTION__.EXT;
|
||||
|
||||
// Function has been called
|
||||
self::$called[__FUNCTION__] = TRUE;
|
||||
}
|
||||
|
||||
return _str_pad($str, $final_str_length, $pad_str, $pad_type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a UTF-8 string to an array. This is a UTF8-aware version of
|
||||
* [str_split](http://php.net/str_split).
|
||||
*
|
||||
* $array = UTF8::str_split($str);
|
||||
*
|
||||
* @author Harry Fuecks <hfuecks@gmail.com>
|
||||
* @param string input string
|
||||
* @param integer maximum length of each chunk
|
||||
* @return array
|
||||
*/
|
||||
public static function str_split($str, $split_length = 1)
|
||||
{
|
||||
if ( ! isset(self::$called[__FUNCTION__]))
|
||||
{
|
||||
require SYSPATH.'utf8'.DIRECTORY_SEPARATOR.__FUNCTION__.EXT;
|
||||
|
||||
// Function has been called
|
||||
self::$called[__FUNCTION__] = TRUE;
|
||||
}
|
||||
|
||||
return _str_split($str, $split_length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverses a UTF-8 string. This is a UTF8-aware version of [strrev](http://php.net/strrev).
|
||||
*
|
||||
* $str = UTF8::strrev($str);
|
||||
*
|
||||
* @author Harry Fuecks <hfuecks@gmail.com>
|
||||
* @param string string to be reversed
|
||||
* @return string
|
||||
*/
|
||||
public static function strrev($str)
|
||||
{
|
||||
if ( ! isset(self::$called[__FUNCTION__]))
|
||||
{
|
||||
require SYSPATH.'utf8'.DIRECTORY_SEPARATOR.__FUNCTION__.EXT;
|
||||
|
||||
// Function has been called
|
||||
self::$called[__FUNCTION__] = TRUE;
|
||||
}
|
||||
|
||||
return _strrev($str);
|
||||
}
|
||||
|
||||
/**
|
||||
* Strips whitespace (or other UTF-8 characters) from the beginning and
|
||||
* end of a string. This is a UTF8-aware version of [trim](http://php.net/trim).
|
||||
*
|
||||
* $str = UTF8::trim($str);
|
||||
*
|
||||
* @author Andreas Gohr <andi@splitbrain.org>
|
||||
* @param string input string
|
||||
* @param string string of characters to remove
|
||||
* @return string
|
||||
*/
|
||||
public static function trim($str, $charlist = NULL)
|
||||
{
|
||||
if ( ! isset(self::$called[__FUNCTION__]))
|
||||
{
|
||||
require SYSPATH.'utf8'.DIRECTORY_SEPARATOR.__FUNCTION__.EXT;
|
||||
|
||||
// Function has been called
|
||||
self::$called[__FUNCTION__] = TRUE;
|
||||
}
|
||||
|
||||
return _trim($str, $charlist);
|
||||
}
|
||||
|
||||
/**
|
||||
* Strips whitespace (or other UTF-8 characters) from the beginning of
|
||||
* a string. This is a UTF8-aware version of [ltrim](http://php.net/ltrim).
|
||||
*
|
||||
* $str = UTF8::ltrim($str);
|
||||
*
|
||||
* @author Andreas Gohr <andi@splitbrain.org>
|
||||
* @param string input string
|
||||
* @param string string of characters to remove
|
||||
* @return string
|
||||
*/
|
||||
public static function ltrim($str, $charlist = NULL)
|
||||
{
|
||||
if ( ! isset(self::$called[__FUNCTION__]))
|
||||
{
|
||||
require SYSPATH.'utf8'.DIRECTORY_SEPARATOR.__FUNCTION__.EXT;
|
||||
|
||||
// Function has been called
|
||||
self::$called[__FUNCTION__] = TRUE;
|
||||
}
|
||||
|
||||
return _ltrim($str, $charlist);
|
||||
}
|
||||
|
||||
/**
|
||||
* Strips whitespace (or other UTF-8 characters) from the end of a string.
|
||||
* This is a UTF8-aware version of [rtrim](http://php.net/rtrim).
|
||||
*
|
||||
* $str = UTF8::rtrim($str);
|
||||
*
|
||||
* @author Andreas Gohr <andi@splitbrain.org>
|
||||
* @param string input string
|
||||
* @param string string of characters to remove
|
||||
* @return string
|
||||
*/
|
||||
public static function rtrim($str, $charlist = NULL)
|
||||
{
|
||||
if ( ! isset(self::$called[__FUNCTION__]))
|
||||
{
|
||||
require SYSPATH.'utf8'.DIRECTORY_SEPARATOR.__FUNCTION__.EXT;
|
||||
|
||||
// Function has been called
|
||||
self::$called[__FUNCTION__] = TRUE;
|
||||
}
|
||||
|
||||
return _rtrim($str, $charlist);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the unicode ordinal for a character. This is a UTF8-aware
|
||||
* version of [ord](http://php.net/ord).
|
||||
*
|
||||
* $digit = UTF8::ord($character);
|
||||
*
|
||||
* @author Harry Fuecks <hfuecks@gmail.com>
|
||||
* @param string UTF-8 encoded character
|
||||
* @return integer
|
||||
*/
|
||||
public static function ord($chr)
|
||||
{
|
||||
if ( ! isset(self::$called[__FUNCTION__]))
|
||||
{
|
||||
require SYSPATH.'utf8'.DIRECTORY_SEPARATOR.__FUNCTION__.EXT;
|
||||
|
||||
// Function has been called
|
||||
self::$called[__FUNCTION__] = TRUE;
|
||||
}
|
||||
|
||||
return _ord($chr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes an UTF-8 string and returns an array of ints representing the Unicode characters.
|
||||
* Astral planes are supported i.e. the ints in the output can be > 0xFFFF.
|
||||
* Occurrences of the BOM are ignored. Surrogates are not allowed.
|
||||
*
|
||||
* $array = UTF8::to_unicode($str);
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
* The Initial Developer of the Original Code is Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998 the Initial Developer.
|
||||
* Ported to PHP by Henri Sivonen <hsivonen@iki.fi>, see <http://hsivonen.iki.fi/php-utf8/>
|
||||
* Slight modifications to fit with phputf8 library by Harry Fuecks <hfuecks@gmail.com>
|
||||
*
|
||||
* @param string UTF-8 encoded string
|
||||
* @return array unicode code points
|
||||
* @return FALSE if the string is invalid
|
||||
*/
|
||||
public static function to_unicode($str)
|
||||
{
|
||||
if ( ! isset(self::$called[__FUNCTION__]))
|
||||
{
|
||||
require SYSPATH.'utf8'.DIRECTORY_SEPARATOR.__FUNCTION__.EXT;
|
||||
|
||||
// Function has been called
|
||||
self::$called[__FUNCTION__] = TRUE;
|
||||
}
|
||||
|
||||
return _to_unicode($str);
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes an array of ints representing the Unicode characters and returns a UTF-8 string.
|
||||
* Astral planes are supported i.e. the ints in the input can be > 0xFFFF.
|
||||
* Occurrances of the BOM are ignored. Surrogates are not allowed.
|
||||
*
|
||||
* $str = UTF8::to_unicode($array);
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
* The Initial Developer of the Original Code is Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998 the Initial Developer.
|
||||
* Ported to PHP by Henri Sivonen <hsivonen@iki.fi>, see http://hsivonen.iki.fi/php-utf8/
|
||||
* Slight modifications to fit with phputf8 library by Harry Fuecks <hfuecks@gmail.com>.
|
||||
*
|
||||
* @param array unicode code points representing a string
|
||||
* @return string utf8 string of characters
|
||||
* @return boolean FALSE if a code point cannot be found
|
||||
*/
|
||||
public static function from_unicode($arr)
|
||||
{
|
||||
if ( ! isset(self::$called[__FUNCTION__]))
|
||||
{
|
||||
require SYSPATH.'utf8'.DIRECTORY_SEPARATOR.__FUNCTION__.EXT;
|
||||
|
||||
// Function has been called
|
||||
self::$called[__FUNCTION__] = TRUE;
|
||||
}
|
||||
|
||||
return _from_unicode($arr);
|
||||
}
|
||||
|
||||
} // End UTF8
|
||||
|
||||
if (Kohana_UTF8::$server_utf8 === NULL)
|
||||
{
|
||||
// Determine if this server supports UTF-8 natively
|
||||
Kohana_UTF8::$server_utf8 = extension_loaded('mbstring');
|
||||
}
|
1161
includes/kohana/system/classes/kohana/validate.php
Normal file
1161
includes/kohana/system/classes/kohana/validate.php
Normal file
File diff suppressed because it is too large
Load Diff
23
includes/kohana/system/classes/kohana/validate/exception.php
Normal file
23
includes/kohana/system/classes/kohana/validate/exception.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
/**
|
||||
* @package Kohana
|
||||
* @category Exceptions
|
||||
* @author Kohana Team
|
||||
* @copyright (c) 2009 Kohana Team
|
||||
* @license http://kohanaphp.com/license
|
||||
*/
|
||||
class Kohana_Validate_Exception extends Kohana_Exception {
|
||||
|
||||
/**
|
||||
* @var object Validate instance
|
||||
*/
|
||||
public $array;
|
||||
|
||||
public function __construct(Validate $array, $message = 'Failed to validate array', array $values = NULL, $code = 0)
|
||||
{
|
||||
$this->array = $array;
|
||||
|
||||
parent::__construct($message, $values, $code);
|
||||
}
|
||||
|
||||
} // End Kohana_Validate_Exception
|
346
includes/kohana/system/classes/kohana/view.php
Normal file
346
includes/kohana/system/classes/kohana/view.php
Normal file
@@ -0,0 +1,346 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
/**
|
||||
* Acts as an object wrapper for HTML pages with embedded PHP, called "views".
|
||||
* Variables can be assigned with the view object and referenced locally within
|
||||
* the view.
|
||||
*
|
||||
* @package Kohana
|
||||
* @category Base
|
||||
* @author Kohana Team
|
||||
* @copyright (c) 2008-2009 Kohana Team
|
||||
* @license http://kohanaphp.com/license
|
||||
*/
|
||||
class Kohana_View {
|
||||
|
||||
// Array of global variables
|
||||
protected static $_global_data = array();
|
||||
|
||||
/**
|
||||
* Returns a new View object. If you do not define the "file" parameter,
|
||||
* you must call [View::set_filename].
|
||||
*
|
||||
* $view = View::factory($file);
|
||||
*
|
||||
* @param string view filename
|
||||
* @param array array of values
|
||||
* @return View
|
||||
*/
|
||||
public static function factory($file = NULL, array $data = NULL)
|
||||
{
|
||||
return new View($file, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Captures the output that is generated when a view is included.
|
||||
* The view data will be extracted to make local variables. This method
|
||||
* is static to prevent object scope resolution.
|
||||
*
|
||||
* $output = View::capture($file, $data);
|
||||
*
|
||||
* @param string filename
|
||||
* @param array variables
|
||||
* @return string
|
||||
*/
|
||||
protected static function capture($kohana_view_filename, array $kohana_view_data)
|
||||
{
|
||||
// Import the view variables to local namespace
|
||||
extract($kohana_view_data, EXTR_SKIP);
|
||||
|
||||
if (View::$_global_data)
|
||||
{
|
||||
// Import the global view variables to local namespace and maintain references
|
||||
extract(View::$_global_data, EXTR_REFS);
|
||||
}
|
||||
|
||||
// Capture the view output
|
||||
ob_start();
|
||||
|
||||
try
|
||||
{
|
||||
// Load the view within the current scope
|
||||
include $kohana_view_filename;
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
// Delete the output buffer
|
||||
ob_end_clean();
|
||||
|
||||
// Re-throw the exception
|
||||
throw $e;
|
||||
}
|
||||
|
||||
// Get the captured output and close the buffer
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a global variable, similar to [View::set], except that the
|
||||
* variable will be accessible to all views.
|
||||
*
|
||||
* View::set_global($name, $value);
|
||||
*
|
||||
* @param string variable name or an array of variables
|
||||
* @param mixed value
|
||||
* @return void
|
||||
*/
|
||||
public static function set_global($key, $value = NULL)
|
||||
{
|
||||
if (is_array($key))
|
||||
{
|
||||
foreach ($key as $key2 => $value)
|
||||
{
|
||||
View::$_global_data[$key2] = $value;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
View::$_global_data[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns a global variable by reference, similar to [View::bind], except
|
||||
* that the variable will be accessible to all views.
|
||||
*
|
||||
* View::bind_global($key, $value);
|
||||
*
|
||||
* @param string variable name
|
||||
* @param mixed referenced variable
|
||||
* @return void
|
||||
*/
|
||||
public static function bind_global($key, & $value)
|
||||
{
|
||||
View::$_global_data[$key] =& $value;
|
||||
}
|
||||
|
||||
// View filename
|
||||
protected $_file;
|
||||
|
||||
// Array of local variables
|
||||
protected $_data = array();
|
||||
|
||||
/**
|
||||
* Sets the initial view filename and local data. Views should almost
|
||||
* always only be created using [View::factory].
|
||||
*
|
||||
* $view = new View($file);
|
||||
*
|
||||
* @param string view filename
|
||||
* @param array array of values
|
||||
* @return void
|
||||
* @uses View::set_filename
|
||||
*/
|
||||
public function __construct($file = NULL, array $data = NULL)
|
||||
{
|
||||
if ($file !== NULL)
|
||||
{
|
||||
$this->set_filename($file);
|
||||
}
|
||||
|
||||
if ( $data !== NULL)
|
||||
{
|
||||
// Add the values to the current data
|
||||
$this->_data = $data + $this->_data;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic method, searches for the given variable and returns its value.
|
||||
* Local variables will be returned before global variables.
|
||||
*
|
||||
* $value = $view->foo;
|
||||
*
|
||||
* [!!] If the variable has not yet been set, an exception will be thrown.
|
||||
*
|
||||
* @param string variable name
|
||||
* @return mixed
|
||||
* @throws Kohana_Exception
|
||||
*/
|
||||
public function & __get($key)
|
||||
{
|
||||
if (isset($this->_data[$key]))
|
||||
{
|
||||
return $this->_data[$key];
|
||||
}
|
||||
elseif (isset(View::$_global_data[$key]))
|
||||
{
|
||||
return View::$_global_data[$key];
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Kohana_Exception('View variable is not set: :var',
|
||||
array(':var' => $key));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic method, calls [View::set] with the same parameters.
|
||||
*
|
||||
* $view->foo = 'something';
|
||||
*
|
||||
* @param string variable name
|
||||
* @param mixed value
|
||||
* @return void
|
||||
*/
|
||||
public function __set($key, $value)
|
||||
{
|
||||
$this->set($key, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic method, determines if a variable is set.
|
||||
*
|
||||
* isset($view->foo);
|
||||
*
|
||||
* [!!] `NULL` variables are not considered to be set by [isset](http://php.net/isset).
|
||||
*
|
||||
* @param string variable name
|
||||
* @return boolean
|
||||
*/
|
||||
public function __isset($key)
|
||||
{
|
||||
return (isset($this->_data[$key]) OR isset(View::$_global_data[$key]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic method, unsets a given variable.
|
||||
*
|
||||
* unset($view->foo);
|
||||
*
|
||||
* @param string variable name
|
||||
* @return void
|
||||
*/
|
||||
public function __unset($key)
|
||||
{
|
||||
unset($this->_data[$key], View::$_global_data[$key]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic method, returns the output of [View::render].
|
||||
*
|
||||
* @return string
|
||||
* @uses View::render
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
try
|
||||
{
|
||||
return $this->render();
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
// Display the exception message
|
||||
Kohana::exception_handler($e);
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the view filename.
|
||||
*
|
||||
* $view->set_filename($file);
|
||||
*
|
||||
* @param string view filename
|
||||
* @return View
|
||||
* @throws Kohana_View_Exception
|
||||
*/
|
||||
public function set_filename($file)
|
||||
{
|
||||
if (($path = Kohana::find_file('views', $file)) === FALSE)
|
||||
{
|
||||
throw new Kohana_View_Exception('The requested view :file could not be found', array(
|
||||
':file' => $file,
|
||||
));
|
||||
}
|
||||
|
||||
// Store the file path locally
|
||||
$this->_file = $path;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns a variable by name. Assigned values will be available as a
|
||||
* variable within the view file:
|
||||
*
|
||||
* // This value can be accessed as $foo within the view
|
||||
* $view->set('foo', 'my value');
|
||||
*
|
||||
* You can also use an array to set several values at once:
|
||||
*
|
||||
* // Create the values $food and $beverage in the view
|
||||
* $view->set(array('food' => 'bread', 'beverage' => 'water'));
|
||||
*
|
||||
* @param string variable name or an array of variables
|
||||
* @param mixed value
|
||||
* @return $this
|
||||
*/
|
||||
public function set($key, $value = NULL)
|
||||
{
|
||||
if (is_array($key))
|
||||
{
|
||||
foreach ($key as $name => $value)
|
||||
{
|
||||
$this->_data[$name] = $value;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->_data[$key] = $value;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns a value by reference. The benefit of binding is that values can
|
||||
* be altered without re-setting them. It is also possible to bind variables
|
||||
* before they have values. Assigned values will be available as a
|
||||
* variable within the view file:
|
||||
*
|
||||
* // This reference can be accessed as $ref within the view
|
||||
* $view->bind('ref', $bar);
|
||||
*
|
||||
* @param string variable name
|
||||
* @param mixed referenced variable
|
||||
* @return $this
|
||||
*/
|
||||
public function bind($key, & $value)
|
||||
{
|
||||
$this->_data[$key] =& $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the view object to a string. Global and local data are merged
|
||||
* and extracted to create local variables within the view file.
|
||||
*
|
||||
* $output = $view->render();
|
||||
*
|
||||
* [!!] Global variables with the same key name as local variables will be
|
||||
* overwritten by the local variable.
|
||||
*
|
||||
* @param string view filename
|
||||
* @return string
|
||||
* @throws Kohana_View_Exception
|
||||
* @uses View::capture
|
||||
*/
|
||||
public function render($file = NULL)
|
||||
{
|
||||
if ($file !== NULL)
|
||||
{
|
||||
$this->set_filename($file);
|
||||
}
|
||||
|
||||
if (empty($this->_file))
|
||||
{
|
||||
throw new Kohana_View_Exception('You must set the file to use within your view before rendering');
|
||||
}
|
||||
|
||||
// Combine local and global data and capture the output
|
||||
return View::capture($this->_file, $this->_data);
|
||||
}
|
||||
|
||||
} // End View
|
9
includes/kohana/system/classes/kohana/view/exception.php
Normal file
9
includes/kohana/system/classes/kohana/view/exception.php
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
/**
|
||||
* @package Kohana
|
||||
* @category Exceptions
|
||||
* @author Kohana Team
|
||||
* @copyright (c) 2009 Kohana Team
|
||||
* @license http://kohanaphp.com/license
|
||||
*/
|
||||
class Kohana_View_Exception extends Kohana_Exception { }
|
3
includes/kohana/system/classes/model.php
Normal file
3
includes/kohana/system/classes/model.php
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
abstract class Model extends Kohana_Model {}
|
3
includes/kohana/system/classes/num.php
Normal file
3
includes/kohana/system/classes/num.php
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
class Num extends Kohana_Num {}
|
3
includes/kohana/system/classes/profiler.php
Normal file
3
includes/kohana/system/classes/profiler.php
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
class Profiler extends Kohana_Profiler {}
|
3
includes/kohana/system/classes/remote.php
Normal file
3
includes/kohana/system/classes/remote.php
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
class Remote extends Kohana_Remote {}
|
3
includes/kohana/system/classes/request.php
Normal file
3
includes/kohana/system/classes/request.php
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
class Request extends Kohana_Request {}
|
3
includes/kohana/system/classes/route.php
Normal file
3
includes/kohana/system/classes/route.php
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
class Route extends Kohana_Route {}
|
3
includes/kohana/system/classes/security.php
Normal file
3
includes/kohana/system/classes/security.php
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
class Security extends Kohana_Security {}
|
3
includes/kohana/system/classes/session.php
Normal file
3
includes/kohana/system/classes/session.php
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
abstract class Session extends Kohana_Session {}
|
3
includes/kohana/system/classes/session/cookie.php
Normal file
3
includes/kohana/system/classes/session/cookie.php
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
class Session_Cookie extends Kohana_Session_Cookie {}
|
3
includes/kohana/system/classes/session/native.php
Normal file
3
includes/kohana/system/classes/session/native.php
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
class Session_Native extends Kohana_Session_Native {}
|
3
includes/kohana/system/classes/text.php
Normal file
3
includes/kohana/system/classes/text.php
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
class Text extends Kohana_Text {}
|
3
includes/kohana/system/classes/upload.php
Normal file
3
includes/kohana/system/classes/upload.php
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
class Upload extends Kohana_Upload {}
|
3
includes/kohana/system/classes/url.php
Normal file
3
includes/kohana/system/classes/url.php
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
class URL extends Kohana_URL {}
|
3
includes/kohana/system/classes/utf8.php
Normal file
3
includes/kohana/system/classes/utf8.php
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
class UTF8 extends Kohana_UTF8 {}
|
3
includes/kohana/system/classes/validate.php
Normal file
3
includes/kohana/system/classes/validate.php
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
class Validate extends Kohana_Validate {}
|
3
includes/kohana/system/classes/validate/exception.php
Normal file
3
includes/kohana/system/classes/validate/exception.php
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
class Validate_Exception extends Kohana_Validate_Exception {}
|
3
includes/kohana/system/classes/view.php
Normal file
3
includes/kohana/system/classes/view.php
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
class View extends Kohana_View {}
|
Reference in New Issue
Block a user