Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Updated Kohana to r4724

  • Loading branch information...
commit 9285c8c66c530196399eb05bb5561c3fa5538335 1 parent 9c5df1d
@bharat bharat authored
Showing with 458 additions and 3,158 deletions.
  1. +3 −0  system/config/cache.php
  2. +2 −1  system/config/database.php
  3. +34 −5 system/core/Kohana.php
  4. +2 −2 system/core/Kohana_Exception.php
  5. +1 −27 system/helpers/form.php
  6. +3 −3 system/helpers/inflector.php
  7. +2 −2 system/helpers/request.php
  8. +1 −12 system/helpers/security.php
  9. +28 −18 system/helpers/text.php
  10. +15 −6 system/helpers/url.php
  11. +1 −1  system/helpers/utf8.php
  12. +83 −4 system/libraries/Cache.php
  13. +1 −7 system/libraries/Controller.php
  14. +13 −10 system/libraries/Database.php
  15. +88 −15 system/libraries/Database_Builder.php
  16. +4 −5 system/libraries/Database_Mysql.php
  17. +16 −16 system/libraries/Database_Mysqli.php
  18. +4 −4 system/libraries/Input.php
  19. +2 −2 system/libraries/Kohana_PHP_Exception.php
  20. +32 −24 system/libraries/ORM.php
  21. +2 −2 system/libraries/Profiler.php
  22. +5 −5 system/libraries/Router.php
  23. +84 −71 system/libraries/Validation.php
  24. +2 −2 system/libraries/drivers/Cache/File.php
  25. +5 −2 system/libraries/drivers/Cache/Memcache.php
  26. +1 −1  system/libraries/drivers/Cache/Xcache.php
  27. +7 −2 system/messages/core.php
  28. +17 −0 system/messages/validation/default.php
  29. +0 −2,909 system/vendor/Markdown.php
View
3  system/config/cache.php
@@ -19,10 +19,13 @@
* thirty minutes. Specific lifetime can also be set when creating a new cache.
* Setting this to 0 will never automatically delete caches.
*
+ * prefix - Adds a prefix to all keys and tags. This can have a severe performance impact.
+ *
*/
$config['default'] = array
(
'driver' => 'file',
'params' => array('directory' => APPPATH.'cache', 'gc_probability' => 1000),
'lifetime' => 1800,
+ 'prefix' => NULL
);
View
3  system/config/database.php
@@ -35,7 +35,8 @@
'host' => 'localhost',
'port' => FALSE,
'socket' => FALSE,
- 'database' => 'kohana'
+ 'database' => 'kohana',
+ 'params' => NULL,
),
'character_set' => 'utf8',
'table_prefix' => '',
View
39 system/core/Kohana.php
@@ -2,7 +2,7 @@
/**
* Provides Kohana-specific helper functions. This is where the magic happens!
*
- * $Id: Kohana.php 4679 2009-11-10 01:45:52Z isaiah $
+ * $Id: Kohana.php 4724 2009-12-21 16:28:54Z isaiah $
*
* @package Core
* @author Kohana Team
@@ -45,6 +45,9 @@
protected static $internal_cache_key;
protected static $internal_cache_encrypt;
+ // Server API that PHP is using. Allows testing of different APIs.
+ public static $server_api = PHP_SAPI;
+
/**
* Sets up the PHP environment. Adds error/exception handling, output
* buffering, and adds an auto-loading method for loading classes.
@@ -162,6 +165,35 @@ public static function setup()
// Set and validate the timezone
date_default_timezone_set(Kohana::config('locale.timezone'));
+ // register_globals is enabled
+ if (ini_get('register_globals'))
+ {
+ if (isset($_REQUEST['GLOBALS']))
+ {
+ // Prevent GLOBALS override attacks
+ exit('Global variable overload attack.');
+ }
+
+ // Destroy the REQUEST global
+ $_REQUEST = array();
+
+ // These globals are standard and should not be removed
+ $preserve = array('GLOBALS', '_REQUEST', '_GET', '_POST', '_FILES', '_COOKIE', '_SERVER', '_ENV', '_SESSION');
+
+ // This loop has the same effect as disabling register_globals
+ foreach (array_diff(array_keys($GLOBALS), $preserve) as $key)
+ {
+ global $$key;
+ $$key = NULL;
+
+ // Unset the global variable
+ unset($GLOBALS[$key], $$key);
+ }
+
+ // Warn the developer about register globals
+ Kohana_Log::add('debug', 'Disable register_globals! It is evil and deprecated: http://php.net/register_globals');
+ }
+
// Enable Kohana routing
Event::add('system.routing', array('Router', 'find_uri'));
Event::add('system.routing', array('Router', 'setup'));
@@ -602,7 +634,7 @@ public static function render($output)
header('Content-Encoding: '.$compress);
// Sending Content-Length in CGI can result in unexpected behavior
- if (stripos(PHP_SAPI, 'cgi') === FALSE)
+ if (stripos(Kohana::$server_api, 'cgi') === FALSE)
{
header('Content-Length: '.strlen($output));
}
@@ -876,9 +908,6 @@ public static function message($key, $args = array())
$group = explode('.', $key, 2);
$group = $group[0];
- // Get locale name
- $locale = Kohana::config('locale.language.0');
-
if ( ! isset(Kohana::$internal_cache['messages'][$group]))
{
// Messages for this group
View
4 system/core/Kohana_Exception.php
@@ -2,7 +2,7 @@
/**
* Kohana Exceptions
*
- * $Id: Kohana_Exception.php 4679 2009-11-10 01:45:52Z isaiah $
+ * $Id: Kohana_Exception.php 4692 2009-12-04 15:59:44Z cbandy $
*
* @package Core
* @author Kohana Team
@@ -197,7 +197,7 @@ public static function handle(Exception $e)
echo Kohana_Exception::text($e), "\n";
}
- if (PHP_SAPI === 'cli')
+ if (Kohana::$server_api === 'cli')
{
// Exit with an error status
exit(1);
View
28 system/helpers/form.php
@@ -2,7 +2,7 @@
/**
* Form helper class.
*
- * $Id: form.php 4679 2009-11-10 01:45:52Z isaiah $
+ * $Id: form.php 4699 2009-12-08 18:45:14Z isaiah $
*
* @package Core
* @author Kohana Team
@@ -421,32 +421,6 @@ public static function attributes($attr, $type = NULL)
if (empty($attr))
return '';
- if (isset($attr['name']) AND empty($attr['id']) AND strpos($attr['name'], '[') === FALSE)
- {
- if ($type === NULL AND ! empty($attr['type']))
- {
- // Set the type by the attributes
- $type = $attr['type'];
- }
-
- switch ($type)
- {
- case 'text':
- case 'textarea':
- case 'password':
- case 'select':
- case 'checkbox':
- case 'file':
- case 'image':
- case 'button':
- case 'submit':
- case 'hidden':
- // Only specific types of inputs use name to id matching
- $attr['id'] = $attr['name'];
- break;
- }
- }
-
$order = array
(
'action',
View
6 system/helpers/inflector.php
@@ -2,7 +2,7 @@
/**
* Inflector helper class.
*
- * $Id: inflector.php 4679 2009-11-10 01:45:52Z isaiah $
+ * $Id: inflector.php 4722 2009-12-19 17:47:34Z isaiah $
*
* @package Core
* @author Kohana Team
@@ -241,9 +241,9 @@ public static function underscore($str)
}
/**
- * Makes an underscored or dashed phrase human-reable.
+ * Makes an underscored or dashed phrase human-readable.
*
- * @param string phrase to make human-reable
+ * @param string phrase to make human-readable
* @return string
*/
public static function humanize($str)
View
4 system/helpers/request.php
@@ -2,7 +2,7 @@
/**
* Request helper class.
*
- * $Id: request.php 4679 2009-11-10 01:45:52Z isaiah $
+ * $Id: request.php 4692 2009-12-04 15:59:44Z cbandy $
*
* @package Core
* @author Kohana Team
@@ -61,7 +61,7 @@ public static function referrer($default = FALSE, $remove_base = FALSE)
*/
public static function protocol()
{
- if (PHP_SAPI === 'cli')
+ if (Kohana::$server_api === 'cli')
{
return NULL;
}
View
13 system/helpers/security.php
@@ -2,7 +2,7 @@
/**
* Security helper class.
*
- * $Id: security.php 4679 2009-11-10 01:45:52Z isaiah $
+ * $Id: security.php 4698 2009-12-08 18:39:33Z isaiah $
*
* @package Core
* @author Kohana Team
@@ -34,15 +34,4 @@ public static function strip_image_tags($str)
return preg_replace('#<img\s.*?(?:src\s*=\s*["\']?([^"\'<>\s]*)["\']?[^>]*)?>#is', '$1', $str);
}
- /**
- * Remove PHP tags from a string.
- *
- * @param string string to sanitize
- * @return string
- */
- public static function encode_php_tags($str)
- {
- return str_replace(array('<?', '?>'), array('&lt;?', '?&gt;'), $str);
- }
-
} // End security
View
46 system/helpers/text.php
@@ -2,7 +2,7 @@
/**
* Text helper class.
*
- * $Id: text.php 4679 2009-11-10 01:45:52Z isaiah $
+ * $Id: text.php 4689 2009-12-02 01:39:24Z isaiah $
*
* @package Core
* @author Kohana Team
@@ -298,27 +298,37 @@ public static function distance($string1, $string2)
*/
public static function auto_link_urls($text)
{
- // Finds all http/https/ftp/ftps links that are not part of an existing html anchor
- if (preg_match_all('~\b(?<!href="|">)(?:ht|f)tps?://\S+(?:/|\b)~i', $text, $matches))
- {
- foreach ($matches[0] as $match)
- {
- // Replace each link with an anchor
- $text = str_replace($match, html::anchor($match), $text);
- }
- }
- // Find all naked www.links.com (without http://)
- if (preg_match_all('~\b(?<!://)www(?:\.[a-z0-9][-a-z0-9]*+)+\.[a-z]{2,6}\b~i', $text, $matches))
+ $regex = '~\\b'
+ .'((?:ht|f)tps?://)?' // protocol
+ .'(?:[-a-zA-Z0-9]{1,63}\.)+' // host name
+ .'(?:[0-9]{1,3}|aero|asia|biz|cat|com|coop|edu|gov|info|int|jobs|mil|mobi|museum|name|net|org|pro|tel|travel|ac|ad|ae|af|ag|ai|al|am|an|ao|aq|ar|as|at|au|aw|ax|az|ba|bb|bd|be|bf|bg|bh|bi|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co|cr|cu|cv|cx|cy|cz|de|dj|dk|dm|do|dz|ec|ee|eg|er|es|et|eu|fi|fj|fk|fm|fo|fr|ga|gb|gd|ge|gf|gg|gh|gi|gl|gm|gn|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|ht|hu|id|ie|il|im|in|io|iq|ir|is|it|je|jm|jo|jp|ke|kg|kh|ki|km|kn|kp|kr|kw|ky|kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|ma|mc|md|me|mg|mh|mk|ml|mm|mn|mo|mp|mq|mr|ms|mt|mu|mv|mw|mx|my|mz|na|nc|ne|nf|ng|ni|nl|no|np|nr|nu|nz|om|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|ps|pt|pw|py|qa|re|ro|rs|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj|sk|sl|sm|sn|so|sr|st|su|sv|sy|sz|tc|td|tf|tg|th|tj|tk|tl|tm|tn|to|tp|tr|tt|tv|tw|tz|ua|ug|uk|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|yu|za|zm|zw)' // tlds
+ .'(?:/[!$-/0-9:;=@_\':;!a-zA-Z\x7f-\xff]*?)?' // path
+ .'(?:\?[!$-/0-9:;=@_\':;!a-zA-Z\x7f-\xff]+?)?' // query
+ .'(?:#[!$-/0-9:;=@_\':;!a-zA-Z\x7f-\xff]+?)?' // fragment
+ .'(?=[?.!,;:"]?(?:\s|$))~'; // punctuation and url end
+
+ $result = "";
+ $position = 0;
+
+ while (preg_match($regex, $text, $match, PREG_OFFSET_CAPTURE, $position))
{
- foreach ($matches[0] as $match)
- {
- // Replace each link with an anchor
- $text = str_replace($match, html::anchor('http://'.$match, $match), $text);
- }
+ list($url, $url_pos) = $match[0];
+
+ // Add the text before the url
+ $result .= substr($text, $position, $url_pos - $position);
+
+ // Default to http://
+ $full_url = empty($match[1][0]) ? 'http://'.$url : $url;
+
+ // Add the hyperlink.
+ $result .= html::anchor($full_url, $url);
+
+ // New position to start parsing
+ $position = $url_pos + strlen($url);
}
- return $text;
+ return $result.substr($text, $position);
}
/**
View
21 system/helpers/url.php
@@ -2,7 +2,7 @@
/**
* URL helper class.
*
- * $Id: url.php 4679 2009-11-10 01:45:52Z isaiah $
+ * $Id: url.php 4685 2009-11-30 21:24:06Z isaiah $
*
* @package Core
* @author Kohana Team
@@ -160,17 +160,26 @@ public static function merge(array $arguments)
*
* @param string phrase to convert
* @param string word separator (- or _)
+ * @param boolean transliterate to ASCII
* @return string
*/
- public static function title($title, $separator = '-')
+ public static function title($title, $separator = '-', $ascii_only = FALSE)
{
$separator = ($separator === '-') ? '-' : '_';
- // Replace accented characters by their unaccented equivalents
- $title = text::transliterate_to_ascii($title);
+ if ($ascii_only === TRUE)
+ {
+ // Replace accented characters by their unaccented equivalents
+ $title = text::transliterate_to_ascii($title);
- // Remove all characters that are not the separator, a-z, 0-9, or whitespace
- $title = preg_replace('/[^'.$separator.'a-z0-9\s]+/', '', strtolower($title));
+ // Remove all characters that are not the separator, a-z, 0-9, or whitespace
+ $title = preg_replace('/[^'.$separator.'a-z0-9\s]+/', '', strtolower($title));
+ }
+ else
+ {
+ // Remove all characters that are not the separator, letters, numbers, or whitespace
+ $title = preg_replace('/[^'.$separator.'\pL\pN\s]+/u', '', mb_strtolower($title));
+ }
// Replace all separator characters and whitespace by a single separator
$title = preg_replace('/['.$separator.'\s]+/', $separator, $title);
View
2  system/helpers/utf8.php
@@ -21,7 +21,7 @@
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt
*/
-class utf8 {
+class utf8_Core {
/**
* Replaces text within a portion of a UTF-8 string.
View
87 system/libraries/Cache.php
@@ -52,7 +52,7 @@ public function __construct($config = FALSE)
// Test the config group name
if (($config = Kohana::config('cache.'.$config)) === NULL)
- throw new Kohana_Exception('The :group: group is not defined in your configuration.', array(':group:' => $name));
+ throw new Cache_Exception('The :group: group is not defined in your configuration.', array(':group:' => $name));
}
if (is_array($config))
@@ -74,7 +74,7 @@ public function __construct($config = FALSE)
// Load the driver
if ( ! Kohana::auto_load($driver))
- throw new Kohana_Exception('The :driver: driver for the :class: library could not be found',
+ throw new Cache_Exception('The :driver: driver for the :class: library could not be found',
array(':driver:' => $this->config['driver'], ':class:' => get_class($this)));
// Initialize the driver
@@ -82,7 +82,7 @@ public function __construct($config = FALSE)
// Validate the driver
if ( ! ($this->driver instanceof Cache_Driver))
- throw new Kohana_Exception('The :driver: driver for the :library: library must implement the :interface: interface',
+ throw new Cache_Exception('The :driver: driver for the :library: library must implement the :interface: interface',
array(':driver:' => $this->config['driver'], ':library:' => get_class($this), ':interface:' => 'Cache_Driver'));
Kohana_Log::add('debug', 'Cache Library initialized');
@@ -103,6 +103,16 @@ public function set($key, $value = NULL, $tags = NULL, $lifetime = NULL)
$key = array($key => $value);
}
+ if ($this->config['prefix'] !== NULL)
+ {
+ $key = $this->add_prefix($key);
+
+ if ($tags !== NULL)
+ {
+ $tags = $this->add_prefix($tags, FALSE);
+ }
+ }
+
return $this->driver->set($key, $tags, $lifetime);
}
@@ -119,6 +129,17 @@ public function get($keys)
$single = TRUE;
}
+ if ($this->config['prefix'] !== NULL)
+ {
+ $keys = $this->add_prefix($keys, FALSE);
+
+ if ( ! $single)
+ {
+ return $this->strip_prefix($this->driver->get($keys, $single));
+ }
+
+ }
+
return $this->driver->get($keys, $single);
}
@@ -132,7 +153,15 @@ public function get_tag($tags)
$tags = array($tags);
}
- return $this->driver->get_tag($tags);
+ if ($this->config['prefix'] !== NULL)
+ {
+ $tags = $this->add_prefix($tags, FALSE);
+ return $this->strip_prefix($this->driver->get_tag($tags));
+ }
+ else
+ {
+ return $this->driver->get_tag($tags);
+ }
}
/**
@@ -145,6 +174,11 @@ public function delete($keys)
$keys = array($keys);
}
+ if ($this->config['prefix'] !== NULL)
+ {
+ $keys = $this->add_prefix($keys, FALSE);
+ }
+
return $this->driver->delete($keys);
}
@@ -158,6 +192,11 @@ public function delete_tag($tags)
$tags = array($tags);
}
+ if ($this->config['prefix'] !== NULL)
+ {
+ $tags = $this->add_prefix($tags, FALSE);
+ }
+
return $this->driver->delete_tag($tags);
}
@@ -168,4 +207,44 @@ public function delete_all()
{
return $this->driver->delete_all();
}
+
+ /**
+ * Add a prefix to keys or tags
+ */
+ protected function add_prefix($array, $to_key = TRUE)
+ {
+ $out = array();
+
+ foreach($array as $key => $value)
+ {
+ if ($to_key)
+ {
+ $out[$this->config['prefix'].$key] = $value;
+ }
+ else
+ {
+ $out[$key] = $this->config['prefix'].$value;
+ }
+ }
+
+ return $out;
+ }
+
+ /**
+ * Strip a prefix to keys or tags
+ */
+ protected function strip_prefix($array)
+ {
+ $out = array();
+
+ $start = strlen($this->config['prefix']);
+
+ foreach($array as $key => $value)
+ {
+ $out[substr($key, $start)] = $value;
+ }
+
+ return $out;
+ }
+
} // End Cache Library
View
8 system/libraries/Controller.php
@@ -3,7 +3,7 @@
* Kohana Controller class. The controller class must be extended to work
* properly, so this class is defined as abstract.
*
- * $Id: Controller.php 4679 2009-11-10 01:45:52Z isaiah $
+ * $Id: Controller.php 4721 2009-12-17 23:02:07Z isaiah $
*
* @package Core
* @author Kohana Team
@@ -27,12 +27,6 @@ public function __construct()
// Set the instance to the first controller loaded
Kohana::$instance = $this;
}
-
- // URI should always be available
- $this->uri = URI::instance();
-
- // Input should always be available
- $this->input = Input::instance();
}
/**
View
23 system/libraries/Database.php
@@ -1,9 +1,9 @@
<?php defined('SYSPATH') or die('No direct script access.');
/**
* Database wrapper.
- *
- * $Id: Database.php 4679 2009-11-10 01:45:52Z isaiah $
- *
+ *
+ * $Id: Database.php 4709 2009-12-10 05:09:35Z isaiah $
+ *
* @package Kohana
* @author Kohana Team
* @copyright (c) 2008-2009 Kohana Team
@@ -11,10 +11,12 @@
*/
abstract class Database_Core {
- const SELECT = 1;
- const INSERT = 2;
- const UPDATE = 3;
- const DELETE = 4;
+ const SELECT = 1;
+ const INSERT = 2;
+ const UPDATE = 3;
+ const DELETE = 4;
+ const CROSS_REQUEST = 5;
+ const PER_REQUEST = 6;
protected static $instances = array();
@@ -350,11 +352,12 @@ protected function query_hash($sql)
* Clears the internal query cache.
*
* @param mixed clear cache by SQL statement, NULL for all, or TRUE for last query
+ * @param integer Type of cache to clear, Database::CROSS_REQUEST or Database::PER_REQUEST
* @return Database
*/
- public function clear_cache($sql = NULL)
+ public function clear_cache($sql = NULL, $type = NULL)
{
- if ($this->cache instanceof Cache)
+ if ($this->cache instanceof Cache AND ($type == NULL OR $type == Database::CROSS_REQUEST))
{
// Using cross-request Cache library
if ($sql === TRUE)
@@ -370,7 +373,7 @@ public function clear_cache($sql = NULL)
$this->cache->delete_all();
}
}
- elseif (is_array($this->cache))
+ elseif (is_array($this->cache) AND ($type == NULL OR $type == Database::PER_REQUEST))
{
// Using per-request memory cache
if ($sql === TRUE)
View
103 system/libraries/Database_Builder.php
@@ -29,6 +29,7 @@ class Database_Builder_Core {
protected $columns = array();
protected $values = array();
protected $type;
+ protected $distinct = FALSE;
// TTL for caching (using Cache library)
protected $ttl = FALSE;
@@ -77,7 +78,8 @@ protected function compile()
if ($this->type === Database::SELECT)
{
// SELECT columns FROM table
- $sql = 'SELECT '.$this->compile_select();
+ $sql = $this->distinct ? 'SELECT DISTINCT ' : 'SELECT ';
+ $sql .= $this->compile_select();
if ( ! empty($this->from))
{
@@ -146,7 +148,13 @@ protected function compile_select()
foreach ($this->select as $alias => $name)
{
- if (is_string($alias))
+ if ($name instanceof Database_Builder)
+ {
+ // Using a subquery
+ $name->db = $this->db;
+ $vals[] = '('.(string) $name.') AS '.$this->db->quote_column($alias);
+ }
+ elseif (is_string($alias))
{
$vals[] = $this->db->quote_column($name, $alias);
}
@@ -374,28 +382,48 @@ public function having($columns, $op = '=', $value = NULL)
/**
* Add conditions to the HAVING clause (AND)
*
- * @param mixed Column name or array of columns => vals
+ * @param mixed Column name or array of triplets
* @param string Operation to perform
* @param mixed Value
* @return Database_Builder
*/
public function and_having($columns, $op = '=', $value = NULL)
{
- $this->having[] = array('AND' => array($columns, $op, $value));
+ if (is_array($columns))
+ {
+ foreach ($columns as $column)
+ {
+ $this->having[] = array('AND' => $column);
+ }
+ }
+ else
+ {
+ $this->having[] = array('AND' => array($columns, $op, $value));
+ }
return $this;
}
/**
* Add conditions to the HAVING clause (OR)
*
- * @param mixed Column name or array of columns => vals
+ * @param mixed Column name or array of triplets
* @param string Operation to perform
* @param mixed Value
* @return Database_Builder
*/
public function or_having($columns, $op = '=', $value = NULL)
{
- $this->having[] = array('OR' => array($columns, $op, $value));
+ if (is_array($columns))
+ {
+ foreach ($columns as $column)
+ {
+ $this->having[] = array('OR' => $column);
+ }
+ }
+ else
+ {
+ $this->having[] = array('OR' => array($columns, $op, $value));
+ }
return $this;
}
@@ -408,13 +436,25 @@ public function or_having($columns, $op = '=', $value = NULL)
*/
public function order_by($columns, $direction = NULL)
{
- if (is_string($columns))
+ if (is_array($columns))
{
- $columns = array($columns => $direction);
+ foreach ($columns as $column => $direction)
+ {
+ if (is_string($column))
+ {
+ $this->order_by[] = array($column => $direction);
+ }
+ else
+ {
+ // $direction is the column name when the array key is numeric
+ $this->order_by[] = array($direction => NULL);
+ }
+ }
+ }
+ else
+ {
+ $this->order_by[] = array($columns => $direction);
}
-
- $this->order_by[] = $columns;
-
return $this;
}
@@ -542,28 +582,48 @@ public function where($columns, $op = '=', $value = NULL)
/**
* Add conditions to the WHERE clause (AND)
*
- * @param mixed Column name or array of columns => vals
+ * @param mixed Column name or array of triplets
* @param string Operation to perform
* @param mixed Value
* @return Database_Builder
*/
public function and_where($columns, $op = '=', $value = NULL)
{
- $this->where[] = array('AND' => array($columns, $op, $value));
+ if (is_array($columns))
+ {
+ foreach ($columns as $column)
+ {
+ $this->where[] = array('AND' => $column);
+ }
+ }
+ else
+ {
+ $this->where[] = array('AND' => array($columns, $op, $value));
+ }
return $this;
}
/**
* Add conditions to the WHERE clause (OR)
*
- * @param mixed Column name or array of columns => vals
+ * @param mixed Column name or array of triplets
* @param string Operation to perform
* @param mixed Value
* @return Database_Builder
*/
public function or_where($columns, $op = '=', $value = NULL)
{
- $this->where[] = array('OR' => array($columns, $op, $value));
+ if (is_array($columns))
+ {
+ foreach ($columns as $column)
+ {
+ $this->where[] = array('OR' => $column);
+ }
+ }
+ else
+ {
+ $this->where[] = array('OR' => array($columns, $op, $value));
+ }
return $this;
}
@@ -780,6 +840,19 @@ public function select($columns = NULL)
}
/**
+ * Create a SELECT query and specify selected columns
+ *
+ * @param string|array column name or array(alias => column)
+ * @return Database_Builder
+ */
+ public function select_distinct($columns = NULL)
+ {
+ $this->select($columns);
+ $this->distinct = TRUE;
+ return $this;
+ }
+
+ /**
* Create an UPDATE query
*
* @param string Table name
View
9 system/libraries/Database_Mysql.php
@@ -2,7 +2,7 @@
/**
* MySQL database connection.
*
- * $Id: Database_Mysql.php 4684 2009-11-18 14:26:48Z isaiah $
+ * $Id: Database_Mysql.php 4712 2009-12-10 21:47:09Z cbandy $
*
* @package Kohana
* @author Kohana Team
@@ -31,16 +31,15 @@ public function connect()
extract($this->config['connection']);
- // Set the connection type
- $connect = ($this->config['persistent'] === TRUE) ? 'mysql_pconnect' : 'mysql_connect';
-
$host = isset($host) ? $host : $socket;
$port = isset($port) ? ':'.$port : '';
try
{
// Connect to the database
- $this->connection = $connect($host.$port, $user, $pass, TRUE);
+ $this->connection = ($this->config['persistent'] === TRUE)
+ ? mysql_pconnect($host.$port, $user, $pass, $params)
+ : mysql_connect($host.$port, $user, $pass, TRUE, $params);
}
catch (Kohana_PHP_Exception $e)
{
View
32 system/libraries/Database_Mysqli.php
@@ -2,7 +2,7 @@
/**
* MySQL database connection.
*
- * $Id: Database_Mysqli.php 4679 2009-11-10 01:45:52Z isaiah $
+ * $Id: Database_Mysqli.php 4712 2009-12-10 21:47:09Z cbandy $
*
* @package Kohana
* @author Kohana Team
@@ -29,29 +29,29 @@ public function connect()
$host = isset($host) ? $host : $socket;
- if($this->connection = new mysqli($host, $user, $pass, $database, $port)) {
+ $mysqli = mysqli_init();
- if (isset($this->config['character_set']))
- {
- // Set the character set
- $this->set_charset($this->config['character_set']);
- }
+ if ( ! $mysqli->real_connect($host, $user, $pass, $database, $port, $socket, $params))
+ throw new Database_Exception('#:errno: :error',
+ array(':error' => $mysqli->connect_error, ':errno' => $mysqli->connect_errno));
- // Clear password after successful connect
- $this->db_config['connection']['pass'] = NULL;
+ $this->connection = $mysqli;
- return $this->connection;
+ if (isset($this->config['character_set']))
+ {
+ // Set the character set
+ $this->set_charset($this->config['character_set']);
}
-
- // Unable to connect to the database
- throw new Database_Exception('#:errno: :error',
- array(':error' => $this->connection->connect_error,
- ':errno' => $this->connection->connect_errno));
}
public function disconnect()
{
- return is_object($this->connection) and $this->connection->close();
+ if (is_object($this->connection))
+ {
+ $this->connection->close();
+ }
+
+ $this->connection = NULL;
}
public function set_charset($charset)
View
8 system/libraries/Input.php
@@ -2,7 +2,7 @@
/**
* Input library.
*
- * $Id: Input.php 4680 2009-11-10 01:57:00Z isaiah $
+ * $Id: Input.php 4720 2009-12-17 21:15:03Z isaiah $
*
* @package Core
* @author Kohana Team
@@ -54,7 +54,7 @@ public function __construct()
$_COOKIE = Input::clean($_COOKIE);
$_SERVER = Input::clean($_SERVER);
- if (PHP_SAPI == 'cli')
+ if (Kohana::$server_api === 'cli')
{
// Convert command line arguments
$_SERVER['argv'] = Input::clean($_SERVER['argv']);
@@ -311,7 +311,7 @@ public function xss_clean($data, $tool = NULL)
if (trim($data) === '')
return $data;
- if ($tool === TRUE)
+ if (is_bool($tool))
{
$tool = 'default';
}
@@ -371,7 +371,7 @@ protected function xss_filter_default($data)
$data = html_entity_decode($data, ENT_COMPAT, 'UTF-8');
// Remove any attribute starting with "on" or xmlns
- $data = preg_replace('#(<[^>]+?[\x00-\x20"\'])(?:on|xmlns)[^>]*+>#iu', '$1>', $data);
+ $data = preg_replace('#(?:on[a-z]+|xmlns)\s*=\s*[\'"\x00-\x20]?[^\'>"]*[\'"\x00-\x20]?\s?#iu', '', $data);
// Remove javascript: and vbscript: protocols
$data = 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...', $data);
View
4 system/libraries/Kohana_PHP_Exception.php
@@ -2,7 +2,7 @@
/**
* Kohana PHP Error Exceptions
*
- * $Id: Kohana_PHP_Exception.php 4679 2009-11-10 01:45:52Z isaiah $
+ * $Id: Kohana_PHP_Exception.php 4687 2009-11-30 21:59:26Z isaiah $
*
* @package Core
* @author Kohana Team
@@ -89,7 +89,7 @@ public static function error_handler($code, $error, $file, $line, $context = NUL
*/
public static function shutdown_handler()
{
- if (Kohana_PHP_Exception::$enabled AND $error = error_get_last())
+ if (Kohana_PHP_Exception::$enabled AND $error = error_get_last() AND (error_reporting() & $error['type']))
{
// Fake an exception for nice debugging
Kohana_Exception::handle(new Kohana_PHP_Exception($error['type'], $error['message'], $error['file'], $error['line']));
View
56 system/libraries/ORM.php
@@ -8,7 +8,7 @@
* [ref-orm]: http://wikipedia.org/wiki/Object-relational_mapping
* [ref-act]: http://wikipedia.org/wiki/Active_record
*
- * $Id: ORM.php 4682 2009-11-11 20:53:23Z isaiah $
+ * $Id: ORM.php 4711 2009-12-10 20:40:52Z isaiah $
*
* @package ORM
* @author Kohana Team
@@ -102,7 +102,7 @@ public function __construct($id = NULL)
$this->object_name = strtolower(substr(get_class($this), 0, -6));
$this->object_plural = inflector::plural($this->object_name);
- if (!isset($this->sorting))
+ if ( ! isset($this->sorting))
{
// Default sorting
$this->sorting = array($this->primary_key => 'asc');
@@ -119,7 +119,7 @@ public function __construct($id = NULL)
// Load an object
$this->_load_values((array) $id);
}
- elseif (!empty($id))
+ elseif ( ! empty($id))
{
// Set the object's primary key, but don't load it until needed
$this->object[$this->primary_key] = $id;
@@ -234,7 +234,7 @@ public function __call($method, array $args)
switch ($num_args)
{
case 0:
- if (in_array($method, array('open', 'close', 'cache')))
+ if (in_array($method, array('open', 'and_open', 'or_open', 'close', 'cache')))
{
// Should return ORM, not Database
$this->db_builder->$method();
@@ -320,12 +320,12 @@ public function __get($column)
}
// Foreign key lies in this table (this model belongs_to target model)
- $where = array($model->foreign_key(TRUE) => $this->object[$this->foreign_key($column)]);
+ $where = array($model->foreign_key(TRUE), '=', $this->object[$this->foreign_key($column)]);
}
else
{
// Foreign key lies in the target table (this model has_one target model)
- $where = array($this->foreign_key($column, $model->table_name) => $this->primary_key_value);
+ $where = array($this->foreign_key($column, $model->table_name), '=', $this->primary_key_value);
}
// one<>alias:one relationship
@@ -525,16 +525,6 @@ public function __unset($column)
}
/**
- * Displays the primary key of a model when it is converted to a string.
- *
- * @return string
- */
- public function __toString()
- {
- return (string) $this->primary_key_value;
- }
-
- /**
* Returns the values of this object as an array.
*
* @return array
@@ -665,7 +655,7 @@ public function find($id = NULL, $ignore_changed = FALSE)
if (is_array($id))
{
// Search for all clauses
- $this->db_builder->where($id);
+ $this->db_builder->where(array($id));
}
else
{
@@ -767,6 +757,9 @@ public function validate(Validation $array = NULL)
ORM_Validation_Exception::handle_validation($this->table_name, $array);
}
+ // Fields may have been modified by filters
+ $this->object = array_merge($this->object, $array->getArrayCopy());
+
// Return validation status
return $this;
}
@@ -782,8 +775,10 @@ public function save()
if ( ! empty($this->changed))
{
// Require model validation before saving
- if (!$this->_valid)
+ if ( ! $this->_valid)
+ {
$this->validate();
+ }
$data = array();
foreach ($this->changed as $column)
@@ -881,8 +876,8 @@ public function save()
}
// Foreign keys for the join table
- $object_fk = $this->foreign_key(NULL);
- $related_fk = $model->foreign_key(NULL);
+ $object_fk = $this->foreign_key($join_table);
+ $related_fk = $model->foreign_key($join_table);
if ( ! empty($added))
{
@@ -909,6 +904,12 @@ public function save()
}
}
+ if ($this->saved() === TRUE)
+ {
+ // Clear the per-request database cache
+ $this->db->clear_cache(NULL, Database::PER_REQUEST);
+ }
+
return $this;
}
@@ -933,6 +934,9 @@ public function delete($id = NULL)
->where($this->primary_key, '=', $id)
->execute($this->db);
+ // Clear the per-request database cache
+ $this->db->clear_cache(NULL, Database::PER_REQUEST);
+
return $this->clear();
}
@@ -965,6 +969,9 @@ public function delete_all($ids = NULL)
return $this;
}
+ // Clear the per-request database cache
+ $this->db->clear_cache(NULL, Database::PER_REQUEST);
+
return $this->clear();
}
@@ -1154,12 +1161,13 @@ public function list_fields()
*
* @chainable
* @param string SQL query to clear
+ * @param integer Type of cache to clear, Database::CROSS_REQUEST or Database::PER_REQUEST
* @return ORM
*/
- public function clear_cache($sql = NULL)
+ public function clear_cache($sql = NULL, $type = NULL)
{
// Proxy to database
- $this->db->clear_cache($sql);
+ $this->db->clear_cache($sql, $type);
ORM::$column_cache = array();
@@ -1550,9 +1558,9 @@ protected function load_result($array = FALSE, $ignore_changed = FALSE)
*/
protected function load_relations($table, ORM $model)
{
- $result = db::select(array('id' => $model->foreign_key(NULL)))
+ $result = db::select(array('id' => $model->foreign_key($table)))
->from($table)
- ->where($this->foreign_key(NULL, $table), '=', $this->primary_key_value)
+ ->where($this->foreign_key($table, $table), '=', $this->primary_key_value)
->execute($this->db)
->as_object();
View
4 system/libraries/Profiler.php
@@ -8,7 +8,7 @@
* POST Data - The name and values of any POST data submitted to the current page.
* Cookie Data - All cookies sent for the current request.
*
- * $Id: Profiler.php 4679 2009-11-10 01:45:52Z isaiah $
+ * $Id: Profiler.php 4719 2009-12-17 04:31:48Z isaiah $
*
* @package Profiler
* @author Kohana Team
@@ -101,7 +101,7 @@ public static function render($return = FALSE)
// Don't display if there's no profiles
if (empty(Profiler::$profiles))
- return $output;
+ return Kohana::$output;
$styles = '';
foreach (Profiler::$profiles as $profile)
View
10 system/libraries/Router.php
@@ -2,7 +2,7 @@
/**
* Router
*
- * $Id: Router.php 4679 2009-11-10 01:45:52Z isaiah $
+ * $Id: Router.php 4693 2009-12-04 17:11:16Z cbandy $
*
* @package Core
* @author Kohana Team
@@ -38,7 +38,7 @@ public static function setup()
if ( ! empty($_SERVER['QUERY_STRING']))
{
// Set the query string to the current query string
- Router::$query_string = '?'.trim(urldecode($_SERVER['QUERY_STRING']), '&/');
+ Router::$query_string = '?'.urldecode(trim($_SERVER['QUERY_STRING'], '&'));
}
if (Router::$routes === NULL)
@@ -173,7 +173,7 @@ public static function setup()
*/
public static function find_uri()
{
- if (PHP_SAPI === 'cli')
+ if (Kohana::$server_api === 'cli')
{
// Command line requires a bit of hacking
if (isset($_SERVER['argv'][1]))
@@ -181,9 +181,9 @@ public static function find_uri()
Router::$current_uri = $_SERVER['argv'][1];
// Remove GET string from segments
- if (($query = strpos(Router::$current_uri, '?')) !== FALSE)
+ if (strpos(Router::$current_uri, '?') !== FALSE)
{
- list (Router::$current_uri, $query) = explode('?', Router::$current_uri, 2);
+ list(Router::$current_uri, $query) = explode('?', Router::$current_uri, 2);
// Parse the query string into $_GET
parse_str($query, $_GET);
View
155 system/libraries/Validation.php
@@ -2,7 +2,7 @@
/**
* Validation library.
*
- * $Id: Validation.php 4679 2009-11-10 01:45:52Z isaiah $
+ * $Id: Validation.php 4713 2009-12-10 22:25:38Z isaiah $
*
* @package Validation
* @author Kohana Team
@@ -26,12 +26,12 @@ class Validation_Core extends ArrayObject {
protected $errors = array();
protected $messages = array();
+ // Field labels
+ protected $labels = array();
+
// Fields that are expected to be arrays
protected $array_fields = array();
- // Checks if there is data to validate.
- protected $submitted;
-
/**
* Creates a new Validation instance.
*
@@ -52,9 +52,6 @@ public static function factory(array $array)
*/
public function __construct(array $array)
{
- // The array is submitted if the array is not empty
- $this->submitted = ! empty($array);
-
parent::__construct($array, ArrayObject::ARRAY_AS_PROPS | ArrayObject::STD_PROP_LIST);
}
@@ -86,21 +83,6 @@ public function copy(array $array)
}
/**
- * Test if the data has been submitted.
- *
- * @return boolean
- */
- public function submitted($value = NULL)
- {
- if (is_bool($value))
- {
- $this->submitted = $value;
- }
-
- return $this->submitted;
- }
-
- /**
* Returns an array of all the field names that have filters, rules, or callbacks.
*
* @return array
@@ -197,6 +179,42 @@ public function allow_empty_rules($rules)
}
/**
+ * Sets or overwrites the label name for a field.
+ *
+ * @param string field name
+ * @param string label
+ * @return $this
+ */
+ public function label($field, $label = NULL)
+ {
+ if ($label === NULL AND ($field !== TRUE OR $field !== '*') AND ! isset($this->labels[$field]))
+ {
+ // Set the field label to the field name
+ $this->labels[$field] = ucfirst(preg_replace('/[^\pL]+/u', ' ', $field));
+ }
+ elseif ($label !== NULL)
+ {
+ // Set the label for this field
+ $this->labels[$field] = $label;
+ }
+
+ return $this;
+ }
+
+ /**
+ * Sets labels using an array.
+ *
+ * @param array list of field => label names
+ * @return $this
+ */
+ public function labels(array $labels)
+ {
+ $this->labels = $labels + $this->labels;
+
+ return $this;
+ }
+
+ /**
* Converts a filter, rule, or callback into a fully-qualified callback array.
*
* @return mixed
@@ -338,6 +356,9 @@ public function add_rules($field, $rules)
$rules = func_get_args();
$rules = array_slice($rules, 1);
+ // Set a default field label
+ $this->label($field);
+
if ($field === TRUE)
{
// Use wildcard
@@ -412,6 +433,9 @@ public function add_callbacks($field, $callbacks)
$callbacks = func_get_args();
$callbacks = array_slice($callbacks, 1);
+ // Set a default field label
+ $this->label($field);
+
if ($field === TRUE)
{
// Use wildcard
@@ -471,9 +495,6 @@ public function validate($object = NULL, $field_name = NULL)
}
}
- if ($this->submitted === FALSE)
- return FALSE;
-
foreach ($this->rules as $field => $callbacks)
{
foreach ($callbacks as $callback)
@@ -534,6 +555,7 @@ public function validate($object = NULL, $field_name = NULL)
if (($result == $is_false))
{
+ $rule = $is_false ? '!'.$rule : $rule;
$this->add_error($field, $rule, $args);
// Stop validating this field when an error is found
@@ -619,46 +641,6 @@ public function add_error($field, $name, $args = NULL)
}
/**
- * Sets or returns the message for an input.
- *
- * @chainable
- * @param string input key
- * @param string message to set
- * @return string|object
- */
- public function message($input = NULL, $message = NULL)
- {
- if ($message === NULL)
- {
- if ($input === NULL)
- {
- $messages = array();
- $keys = array_keys($this->messages);
-
- foreach ($keys as $input)
- {
- $messages[] = $this->message($input);
- }
-
- return implode("\n", $messages);
- }
-
- // Return nothing if no message exists
- if (empty($this->messages[$input]))
- return '';
-
- // Return the HTML message string
- return $this->messages[$input];
- }
- else
- {
- $this->messages[$input] = $message;
- }
-
- return $this;
- }
-
- /**
* Return the errors array.
*
* @param boolean load errors from a message file
@@ -677,18 +659,49 @@ public function errors($file = NULL)
}
else
{
-
$errors = array();
foreach ($this->errors as $input => $error)
{
- // Key for this input error
- $key = "$file.$input.$error[0]";
+ // Locations to check for error messages
+ $error_locations = array
+ (
+ "validation/{$file}.{$input}.{$error[0]}",
+ "validation/{$file}.{$input}.default",
+ "validation/default.{$error[0]}"
+ );
+
+ if (($message = Kohana::message($error_locations[0])) !== $error_locations[0])
+ {
+ // Found a message for this field and error
+ }
+ elseif (($message = Kohana::message($error_locations[1])) !== $error_locations[1])
+ {
+ // Found a default message for this field
+ }
+ elseif (($message = Kohana::message($error_locations[2])) !== $error_locations[2])
+ {
+ // Found a default message for this error
+ }
+ else
+ {
+ // No message exists, display the path expected
+ $message = "validation/{$file}.{$input}.{$error[0]}";
+ }
- if (($errors[$input] = Kohana::message('validation/'.$key, $error[1])) === $key)
+ // Start the translation values list
+ $values = array(':field' => __($this->labels[$input]));
+
+ if ( ! empty($error[1]))
{
- // Get the default error message
- $errors[$input] = Kohana::message("$file.$input.default");
+ foreach ($error[1] as $key => $value)
+ {
+ // Add each parameter as a numbered value, starting from 1
+ $values[':param'.($key + 1)] = __($value);
+ }
}
+
+ // Translate the message using the default language
+ $errors[$input] = __($message, $values);
}
return $errors;
View
4 system/libraries/drivers/Cache/File.php
@@ -183,7 +183,7 @@ public function get_tag($tags)
// Get the id from the filename
list($key, $junk) = explode('~', basename($path), 2);
- if (($data = $this->get($key)) !== FALSE)
+ if (($data = $this->get($key, TRUE)) !== FALSE)
{
// Add the result to the array
$result[$key] = $data;
@@ -211,7 +211,7 @@ public function delete($keys, $tag = FALSE)
// Remove the cache file
if ( ! unlink($path))
{
- Kohana::log('error', 'Cache: Unable to delete cache file: '.$path);
+ Kohana_Log::add('error', 'Cache: Unable to delete cache file: '.$path);
$success = FALSE;
}
}
View
7 system/libraries/drivers/Cache/Memcache.php
@@ -17,7 +17,7 @@ class Cache_Memcache_Driver extends Cache_Driver {
public function __construct($config)
{
if ( ! extension_loaded('memcache'))
- throw new Kohana_Exception('The memcache PHP extension must be loaded to use this driver.');
+ throw new Cache_Exception('The memcache PHP extension must be loaded to use this driver.');
ini_set('memcache.allow_failover', (isset($config['allow_failover']) AND $config['allow_failover']) ? TRUE : FALSE);
@@ -79,7 +79,10 @@ public function get($keys, $single = FALSE)
if ($single)
{
- return ($items === FALSE OR count($items) > 0) ? current($items) : NULL;
+ if ($items === FALSE)
+ return NULL;
+
+ return (count($items) > 0) ? current($items) : NULL;
}
else
{
View
2  system/libraries/drivers/Cache/Xcache.php
@@ -16,7 +16,7 @@ class Cache_Xcache_Driver extends Cache_Driver {
public function __construct($config)
{
if ( ! extension_loaded('xcache'))
- throw new Kohana_Exception('The xcache PHP extension must be loaded to use this driver.');
+ throw new Cache_Exception('The xcache PHP extension must be loaded to use this driver.');
$this->config = $config;
}
View
9 system/messages/core.php
@@ -8,7 +8,6 @@
E_PAGE_NOT_FOUND => __('Page Not Found'), // __('The requested page was not found. It may have moved, been deleted, or archived.'),
E_DATABASE_ERROR => __('Database Error'), // __('A database error occurred while performing the requested procedure. Please review the database error below for more information.'),
E_RECOVERABLE_ERROR => __('Recoverable Error'), // __('An error was detected which prevented the loading of this page. If this problem persists, please contact the website administrator.'),
-
E_ERROR => __('Fatal Error'),
E_COMPILE_ERROR => __('Fatal Error'),
E_CORE_ERROR => __('Fatal Error'),
@@ -29,4 +28,10 @@
'driver' => 'driver',
'model' => 'model',
'view' => 'view',
-);
+);
+
+// E_DEPRECATED is only defined in PHP >= 5.3.0
+if (defined('E_DEPRECATED'))
+{
+ $messages['errors'][E_DEPRECATED] = __('Deprecated');
+}
View
17 system/messages/validation/default.php
@@ -0,0 +1,17 @@
+<?php defined('SYSPATH') or die('No direct script access.');
+
+$messages = array(
+ 'required' => 'The :field field is required',
+ 'length' => 'The :field field must be between :param1 and :param2 characters long',
+ 'depends_on' => 'The :field field requires the :param1 field',
+ 'matches' => 'The :field field must be the same as :param1',
+ 'email' => 'The :field field must be a valid email address',
+ 'decimal' => 'The :field field must be a decimal with :param1 places',
+ 'digit' => 'The :field field must be a digit',
+ 'in_array' => 'The :field field must be one of the available options',
+ 'alpha_numeric' => 'The :field field must consist only of alphabetical or numeric characters',
+ 'alpha_dash ' => 'The :field field must consist only of alphabetical, numeric, underscore and dash characters',
+ 'numeric ' => 'The :field field must be a valid number',
+ 'url' => 'The :field field must be a valid url',
+ 'phone' => 'The :field field must be a valid phone number',
+);
View
2,909 system/vendor/Markdown.php
@@ -1,2909 +0,0 @@
-<?php
-#
-# Markdown Extra - A text-to-HTML conversion tool for web writers
-#
-# PHP Markdown & Extra
-# Copyright (c) 2004-2008 Michel Fortin
-# <http://www.michelf.com/projects/php-markdown/>
-#
-# Original Markdown
-# Copyright (c) 2004-2006 John Gruber
-# <http://daringfireball.net/projects/markdown/>
-#
-
-
-define( 'MARKDOWN_VERSION', "1.0.1m" ); # Sat 21 Jun 2008
-define( 'MARKDOWNEXTRA_VERSION', "1.2.3" ); # Wed 31 Dec 2008
-
-
-#
-# Global default settings:
-#
-
-# Change to ">" for HTML output
-@define( 'MARKDOWN_EMPTY_ELEMENT_SUFFIX', " />");
-
-# Define the width of a tab for code blocks.
-@define( 'MARKDOWN_TAB_WIDTH', 4 );
-
-# Optional title attribute for footnote links and backlinks.
-@define( 'MARKDOWN_FN_LINK_TITLE', "" );
-@define( 'MARKDOWN_FN_BACKLINK_TITLE', "" );
-
-# Optional class attribute for footnote links and backlinks.
-@define( 'MARKDOWN_FN_LINK_CLASS', "" );
-@define( 'MARKDOWN_FN_BACKLINK_CLASS', "" );
-
-
-#
-# WordPress settings:
-#
-
-# Change to false to remove Markdown from posts and/or comments.
-@define( 'MARKDOWN_WP_POSTS', true );
-@define( 'MARKDOWN_WP_COMMENTS', true );
-
-
-
-### Standard Function Interface ###
-
-@define( 'MARKDOWN_PARSER_CLASS', 'MarkdownExtra_Parser' );
-
-function Markdown($text) {
-#
-# Initialize the parser and return the result of its transform method.
-#
- # Setup static parser variable.
- static $parser;
- if (!isset($parser)) {
- $parser_class = MARKDOWN_PARSER_CLASS;
- $parser = new $parser_class;
- }
-
- # Transform text using parser.
- return $parser->transform($text);
-}
-
-
-### WordPress Plugin Interface ###
-
-/*
-Plugin Name: Markdown Extra
-Plugin URI: http://www.michelf.com/projects/php-markdown/
-Description: <a href="http://daringfireball.net/projects/markdown/syntax">Markdown syntax</a> allows you to write using an easy-to-read, easy-to-write plain text format. Based on the original Perl version by <a href="http://daringfireball.net/">John Gruber</a>. <a href="http://www.michelf.com/projects/php-markdown/">More...</a>
-Version: 1.2.2
-Author: Michel Fortin
-Author URI: http://www.michelf.com/
-*/
-
-if (isset($wp_version)) {
- # More details about how it works here:
- # <http://www.michelf.com/weblog/2005/wordpress-text-flow-vs-markdown/>
-
- # Post content and excerpts
- # - Remove WordPress paragraph generator.
- # - Run Markdown on excerpt, then remove all tags.
- # - Add paragraph tag around the excerpt, but remove it for the excerpt rss.
- if (MARKDOWN_WP_POSTS) {
- remove_filter('the_content', 'wpautop');
- remove_filter('the_content_rss', 'wpautop');
- remove_filter('the_excerpt', 'wpautop');
- add_filter('the_content', 'mdwp_MarkdownPost', 6);
- add_filter('the_content_rss', 'mdwp_MarkdownPost', 6);
- add_filter('get_the_excerpt', 'mdwp_MarkdownPost', 6);
- add_filter('get_the_excerpt', 'trim', 7);
- add_filter('the_excerpt', 'mdwp_add_p');
- add_filter('the_excerpt_rss', 'mdwp_strip_p');
-
- remove_filter('content_save_pre', 'balanceTags', 50);
- remove_filter('excerpt_save_pre', 'balanceTags', 50);
- add_filter('the_content', 'balanceTags', 50);
- add_filter('get_the_excerpt', 'balanceTags', 9);
- }
-
- # Add a footnote id prefix to posts when inside a loop.
- function mdwp_MarkdownPost($text) {
- static $parser;
- if (!$parser) {
- $parser_class = MARKDOWN_PARSER_CLASS;
- $parser = new $parser_class;
- }
- if (is_single() || is_page() || is_feed()) {
- $parser->fn_id_prefix = "";
- } else {
- $parser->fn_id_prefix = get_the_ID() . ".";
- }
- return $parser->transform($text);
- }
-
- # Comments
- # - Remove WordPress paragraph generator.
- # - Remove WordPress auto-link generator.
- # - Scramble important tags before passing them to the kses filter.
- # - Run Markdown on excerpt then remove paragraph tags.
- if (MARKDOWN_WP_COMMENTS) {
- remove_filter('comment_text', 'wpautop', 30);
- remove_filter('comment_text', 'make_clickable');
- add_filter('pre_comment_content', 'Markdown', 6);
- add_filter('pre_comment_content', 'mdwp_hide_tags', 8);
- add_filter('pre_comment_content', 'mdwp_show_tags', 12);
- add_filter('get_comment_text', 'Markdown', 6);
- add_filter('get_comment_excerpt', 'Markdown', 6);
- add_filter('get_comment_excerpt', 'mdwp_strip_p', 7);
-
- global $mdwp_hidden_tags, $mdwp_placeholders;
- $mdwp_hidden_tags = explode(' ',
- '<p> </p> <pre> </pre> <ol> </ol> <ul> </ul> <li> </li>');
- $mdwp_placeholders = explode(' ', str_rot13(
- 'pEj07ZbbBZ U1kqgh4w4p pre2zmeN6K QTi31t9pre ol0MP1jzJR '.
- 'ML5IjmbRol ulANi1NsGY J7zRLJqPul liA8ctl16T K9nhooUHli'));
- }
-
- function mdwp_add_p($text) {
- if (!preg_match('{^$|^<(p|ul|ol|dl|pre|blockquote)>}i', $text)) {
- $text = '<p>'.$text.'</p>';
- $text = preg_replace('{\n{2,}}', "</p>\n\n<p>", $text);
- }
- return $text;
- }
-
- function mdwp_strip_p($t) { return preg_replace('{</?p>}i', '', $t); }
-
- function mdwp_hide_tags($text) {
- global $mdwp_hidden_tags, $mdwp_placeholders;
- return str_replace($mdwp_hidden_tags, $mdwp_placeholders, $text);
- }
- function mdwp_show_tags($text) {
- global $mdwp_hidden_tags, $mdwp_placeholders;
- return str_replace($mdwp_placeholders, $mdwp_hidden_tags, $text);
- }
-}
-
-
-### bBlog Plugin Info ###
-
-function identify_modifier_markdown() {
- return array(
- 'name' => 'markdown',
- 'type' => 'modifier',
- 'nicename' => 'PHP Markdown Extra',
- 'description' => 'A text-to-HTML conversion tool for web writers',
- 'authors' => 'Michel Fortin and John Gruber',
- 'licence' => 'GPL',
- 'version' => MARKDOWNEXTRA_VERSION,
- 'help' => '<a href="http://daringfireball.net/projects/markdown/syntax">Markdown syntax</a> allows you to write using an easy-to-read, easy-to-write plain text format. Based on the original Perl version by <a href="http://daringfireball.net/">John Gruber</a>. <a href="http://www.michelf.com/projects/php-markdown/">More...</a>',
- );
-}
-
-
-### Smarty Modifier Interface ###
-
-function smarty_modifier_markdown($text) {
- return Markdown($text);
-}
-
-
-### Textile Compatibility Mode ###
-
-# Rename this file to "classTextile.php" and it can replace Textile everywhere.
-
-if (strcasecmp(substr(__FILE__, -16), "classTextile.php") == 0) {
- # Try to include PHP SmartyPants. Should be in the same directory.
- @include_once 'smartypants.php';
- # Fake Textile class. It calls Markdown instead.
- class Textile {
- function TextileThis($text, $lite='', $encode='') {
- if ($lite == '' && $encode == '') $text = Markdown($text);
- if (function_exists('SmartyPants')) $text = SmartyPants($text);
- return $text;
- }
- # Fake restricted version: restrictions are not supported for now.
- function TextileRestricted($text, $lite='', $noimage='') {
- return $this->TextileThis($text, $lite);
- }
- # Workaround to ensure compatibility with TextPattern 4.0.3.
- function blockLite($text) { return $text; }
- }
-}
-
-
-
-#
-# Markdown Parser Class
-#
-
-class Markdown_Parser {
-
- # Regex to match balanced [brackets].
- # Needed to insert a maximum bracked depth while converting to PHP.
- var $nested_brackets_depth = 6;
- var $nested_brackets_re;
-
- var $nested_url_parenthesis_depth = 4;
- var $nested_url_parenthesis_re;
-
- # Table of hash values for escaped characters:
- var $escape_chars = '\`*_{}[]()>#+-.!';
- var $escape_chars_re;
-
- # Change to ">" for HTML output.
- var $empty_element_suffix = MARKDOWN_EMPTY_ELEMENT_SUFFIX;
- var $tab_width = MARKDOWN_TAB_WIDTH;
-
- # Change to `true` to disallow markup or entities.
- var $no_markup = false;
- var $no_entities = false;
-
- # Predefined urls and titles for reference links and images.
- var $predef_urls = array();
- var $predef_titles = array();
-
-
- function Markdown_Parser() {
- #
- # Constructor function. Initialize appropriate member variables.
- #
- $this->_initDetab();
- $this->prepareItalicsAndBold();
-
- $this->nested_brackets_re =
- str_repeat('(?>[^\[\]]+|\[', $this->nested_brackets_depth).
- str_repeat('\])*', $this->nested_brackets_depth);
-
- $this->nested_url_parenthesis_re =
- str_repeat('(?>[^()\s]+|\(', $this->nested_url_parenthesis_depth).
- str_repeat('(?>\)))*', $this->nested_url_parenthesis_depth);
-
- $this->escape_chars_re = '['.preg_quote($this->escape_chars).']';
-
- # Sort document, block, and span gamut in ascendent priority order.
- asort($this->document_gamut);
- asort($this->block_gamut);
- asort($this->span_gamut);
- }
-
-
- # Internal hashes used during transformation.
- var $urls = array();
- var $titles = array();
- var $html_hashes = array();
-
- # Status flag to avoid invalid nesting.
- var $in_anchor = false;
-
-
- function setup() {
- #
- # Called before the transformation process starts to setup parser
- # states.
- #
- # Clear global hashes.
- $this->urls = $this->predef_urls;
- $this->titles = $this->predef_titles;
- $this->html_hashes = array();
-
- $in_anchor = false;
- }
-
- function teardown() {
- #
- # Called after the transformation process to clear any variable
- # which may be taking up memory unnecessarly.
- #
- $this->urls = array();
- $this->titles = array();
- $this->html_hashes = array();
- }
-
-
- function transform($text) {
- #
- # Main function. Performs some preprocessing on the input text
- # and pass it through the document gamut.
- #
- $this->setup();
-
- # Remove UTF-8 BOM and marker character in input, if present.
- $text = preg_replace('{^\xEF\xBB\xBF|\x1A}', '', $text);
-
- # Standardize line endings:
- # DOS to Unix and Mac to Unix
- $text = preg_replace('{\r\n?}', "\n", $text);
-
- # Make sure $text ends with a couple of newlines:
- $text .= "\n\n";
-
- # Convert all tabs to spaces.
- $text = $this->detab($text);
-
- # Turn block-level HTML blocks into hash entries
- $text = $this->hashHTMLBlocks($text);
-
- # Strip any lines consisting only of spaces and tabs.
- # This makes subsequent regexen easier to write, because we can
- # match consecutive blank lines with /\n+/ instead of something
- # contorted like /[ ]*\n+/ .
- $text = preg_replace('/^[ ]+$/m', '', $text);
-
- # Run document gamut methods.
- foreach ($this->document_gamut as $method => $priority) {
- $text = $this->$method($text);
- }
-
- $this->teardown();
-
- return $text . "\n";
- }
-
- var $document_gamut = array(
- # Strip link definitions, store in hashes.
- "stripLinkDefinitions" => 20,
-
- "runBasicBlockGamut" => 30,
- );
-
-
- function stripLinkDefinitions($text) {
- #
- # Strips link definitions from text, stores the URLs and titles in
- # hash references.
- #
- $less_than_tab = $this->tab_width - 1;
-
- # Link defs are in the form: ^[id]: url "optional title"
- $text = preg_replace_callback('{
- ^[ ]{0,'.$less_than_tab.'}\[(.+)\][ ]?: # id = $1
- [ ]*
- \n? # maybe *one* newline
- [ ]*
- <?(\S+?)>? # url = $2
- [ ]*
- \n? # maybe one newline
- [ ]*
- (?:
- (?<=\s) # lookbehind for whitespace
- ["(]
- (.*?) # title = $3
- [")]
- [ ]*
- )? # title is optional
- (?:\n+|\Z)
- }xm',
- array(&$this, '_stripLinkDefinitions_callback'),
- $text);
- return $text;
- }
- function _stripLinkDefinitions_callback($matches) {
- $link_id = strtolower($matches[1]);
- $this->urls[$link_id] = $matches[2];
- $this->titles[$link_id] =& $matches[3];
- return ''; # String that will replace the block
- }
-
-
- function hashHTMLBlocks($text) {
- if ($this->no_markup) return $text;
-
- $less_than_tab = $this->tab_width - 1;
-
- # Hashify HTML blocks:
- # We only want to do this for block-level HTML tags, such as headers,
- # lists, and tables. That's because we still want to wrap <p>s around
- # "paragraphs" that are wrapped in non-block-level tags, such as anchors,
- # phrase emphasis, and spans. The list of tags we're looking for is
- # hard-coded:
- #
- # * List "a" is made of tags which can be both inline or block-level.
- # These will be treated block-level when the start tag is alone on
- # its line, otherwise they're not matched here and will be taken as
- # inline later.
- # * List "b" is made of tags which are always block-level;
- #
- $block_tags_a_re = 'ins|del';
- $block_tags_b_re = 'p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|address|'.
- 'script|noscript|form|fieldset|iframe|math';
-
- # Regular expression for the content of a block tag.
- $nested_tags_level = 4;
- $attr = '
- (?> # optional tag attributes
- \s # starts with whitespace
- (?>
- [^>"/]+ # text outside quotes
- |
- /+(?!>) # slash not followed by ">"