<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>CTAPbIu_MABP&#039;s BLOG &#187; regex</title>
	<atom:link href="http://mabp.kiev.ua/tag/regex/feed/" rel="self" type="application/rss+xml" />
	<link>http://mabp.kiev.ua</link>
	<description>Не вижу проблем, кроме лени! &#169; Старый Мавр</description>
	<lastBuildDate>Tue, 07 Sep 2010 20:05:40 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Non-triming space</title>
		<link>http://mabp.kiev.ua/2009/12/01/non-triming-space/</link>
		<comments>http://mabp.kiev.ua/2009/12/01/non-triming-space/#comments</comments>
		<pubDate>Tue, 01 Dec 2009 17:16:30 +0000</pubDate>
		<dc:creator>CTAPbIu_MABP</dc:creator>
				<category><![CDATA[JAVA]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Программирование]]></category>
		<category><![CDATA[regex]]></category>

		<guid isPermaLink="false">http://mabp.kiev.ua/?p=1143</guid>
		<description><![CDATA[Когда Женя показал мне свою заметку о неубиваймом пробеле я подумал это недостатки php и сказал, что в Java такой фигни нет и не будет. Оказалось показалось, Java тоже грешит этой фигней.





package ua.kiev.mabp;


/**
 * Created by IntelliJ IDEA.
 * User: CTAPbIu_MABP
 * Date: 01.12.2009
 * Time: 18:48:00
 */
public class TrimDemo {
    public [...]]]></description>
			<content:encoded><![CDATA[<p>Когда Женя показал мне свою <a href="http://vedeney.org.ua/php/trim-function-doesnt-clean-out-ascii-code-160/" rel="nofollow external">заметку</a> о неубиваймом пробеле я подумал это недостатки php и сказал, что в <a href="http://mabp.kiev.ua/category/programming/java/">Java</a> такой фигни нет и не будет. Оказалось показалось, <a href="http://mabp.kiev.ua/category/programming/java/">Java</a> тоже грешит этой фигней.</p>
<span id="more-1143">
</span>
<pre>
<code class="java">

package ua.kiev.mabp;


/**
 * Created by IntelliJ IDEA.
 * User: CTAPbIu_MABP
 * Date: 01.12.2009
 * Time: 18:48:00
 */
public class TrimDemo {
    public static void main(String[] args) {
        System.out.print("".concat(String.valueOf(new char[]{160, 160, 160})).trim().length());
    }
}

</code>
</pre>
<p>И еще <a href="http://www.jstoolbox.com/2009/11/01/funkciya-trim/" rel="nofollow external">лик</a> в тему</p>
<br />
]]></content:encoded>
			<wfw:commentRss>http://mabp.kiev.ua/2009/12/01/non-triming-space/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Code WTF: JavaScript HTML entities</title>
		<link>http://mabp.kiev.ua/2009/07/06/code-wtf-javascript-html-entities/</link>
		<comments>http://mabp.kiev.ua/2009/07/06/code-wtf-javascript-html-entities/#comments</comments>
		<pubDate>Mon, 06 Jul 2009 20:14:32 +0000</pubDate>
		<dc:creator>CTAPbIu_MABP</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Программирование]]></category>
		<category><![CDATA[algorithms]]></category>
		<category><![CDATA[regex]]></category>

		<guid isPermaLink="false">http://mabp.kiev.ua/?p=1083</guid>
		<description><![CDATA[Увидел у Вадима Войтюка в блоге задачку и задело. Это ж делается в одну строку! Ну максимум в две. 10 десять минут дела и один профтык с функцией escape() и все готово.


В общем вот что получилось:



var text = "'s&#60;d\"f&#62;g'q".replace(new RegExp("['\"&#60;&#62;\&#38;]", 'g'), function(s) {
	return {'':'&#38;gt;','&#38;':'&#38;amp;','"':'&#38;quot;','\'':'&#38;#039;'}[s]; 
});
alert(text); // &#38;#039;s&#38;lt;d&#38;quot;f&#38;gt;g&#38;#039;q



А запостил тут, потому что воевать с парсером каментов [...]]]></description>
			<content:encoded><![CDATA[<p>Увидел у <a href="http://voituk.kiev.ua/2009/07/02/javascript-html-entities/" rel="nofollow external">Вадима Войтюка</a> в блоге задачку и задело. Это ж делается в одну строку! Ну максимум в две. 10 десять минут дела и один профтык с функцией escape() и все готово.</p>
<span id="more-1083">
</span>
<p>В общем вот что получилось:</p>
<pre>
<code class="javascript">

var text = "'s&lt;d\"f&gt;g'q".replace(new RegExp("['\"&lt;&gt;\&amp;]", 'g'), function(s) {
	return {'<':'&amp;lt;','>':'&amp;gt;','&amp;':'&amp;amp;','"':'&amp;quot;','\'':'&amp;#039;'}[s]; 
});
alert(text); // &amp;#039;s&amp;lt;d&amp;quot;f&amp;gt;g&amp;#039;q

</code>
</pre>
<p>А запостил тут, потому что воевать с парсером каментов у него в блоге мне лень.</p>]]></content:encoded>
			<wfw:commentRss>http://mabp.kiev.ua/2009/07/06/code-wtf-javascript-html-entities/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Request</title>
		<link>http://mabp.kiev.ua/2008/04/20/request/</link>
		<comments>http://mabp.kiev.ua/2008/04/20/request/#comments</comments>
		<pubDate>Sun, 20 Apr 2008 14:58:46 +0000</pubDate>
		<dc:creator>CTAPbIu_MABP</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Программирование]]></category>
		<category><![CDATA[regex]]></category>

		<guid isPermaLink="false">http://mabp.localhost/?p=174</guid>
		<description><![CDATA[Переносить классы c phpclasses я начал с Cache Manager, а это второй класс под названием Request. Его я люблю не меньше, в основном за его гибкость, он позволяет проверить любую переменную переданную ему на соответствие шаблону. Фактически класс есть оберткой для функции preg_match(), но позволяет не задумываться о параметрах.


Основная задача, которую решает класс - это [...]]]></description>
			<content:encoded><![CDATA[<p>Переносить классы c <a href="http://www.phpclasses.org/browse/author/366148.html" rel="nofollow">phpclasses</a> я начал с <a href="http://mabp.kiev.ua/2008/04/16/cache_manager/" title="Cache Manager">Cache Manager</a>, а это второй класс под названием Request. Его я люблю не меньше, в основном за его гибкость, он позволяет проверить любую переменную переданную ему на соответствие шаблону. Фактически класс есть оберткой для функции preg_match(), но позволяет не задумываться о параметрах.</p>
<span id="more-174">
</span>
<p>Основная задача, которую решает класс - это фильтрация пользовательских данных, что есть неотъемлемой частью безопасности сайта. Например, можно проверять данные из GET запроса, перед тем как использовать их в SQL запросе. Данные можно проверять как из суперглобальных массивов ($_GET, $_POST, $_COOKIE, etc) и просто передать переменную, которую вы хотите проверить по шаблону. Класс предоставляет предустановленный набор таких шаблонов для самых частых проверок таких как цифровые (INT), буквенные (LIT), цифробуквенные (ALN) переменные, также можно валидировать email адреса (EML) и ссылки (URL), или использовать преобразования как например применения функции htmlspecialchars() (TXT) или вырезания специальных символов (SLU). Если вам не хватает готовых правил, вы всегда можете дописать и использовать свои или же передать в класс регулярное выражение вместо названия фильтра.</p>
<pre>
<code class="php">

class Request{


	/**
	 * @author CTAPbIu_MABP
	 * @version 1.5
	 * @license GNU General Public License
	 *
	 */


	private $value  = NULL;					// переменная переменная	#ANY
	private $shield = FALSE;				// щит (выключен)		#bool
	private $maxlen = 0;					// 0 - неограничено		#integer
	private $mode = 'INT';					// фильтр для массивов	#string
	private $quotes = NULL;				// magic quotes gpc		#bool


	/**
	 * Конструктор заполняет основные свойства
	 *
	 * @param boolean $shield
	 * @param string $default
	 */
	public function __construct($shield=FALSE,$default='INT'){
		$this->quotes = (bool)get_magic_quotes_gpc();
		$this->shield = $shield;
		$this->mode = $default;
	}


	/**
	 * Основной метод класса, управляет процессом фильтрации
	 *
	 * @param mixed $name string or array of string
	 * @param string $type name or regexp
	 * @param mixed $source
	 * @param integer $maxlen
	 * @return mixed
	 */
	public function define($name, $type, $source='R', $maxlen=0){
		if (is_array($name)){
			foreach ($name as $single)
				$array[] = $this->define($single, $type, $source, $maxlen);
			return $array;
		}else{
			$this->maxlen = $maxlen;
			$_SOURCE =&#038; $this->source($source, $name);


			if (!array_key_exists($name, $_SOURCE))
				return $this->$name = $this->shield ? $this->log($type, $name) : NULL;
			else {
				$this->type($type, $_SOURCE[$name]);
				if ($this->maxlen > 0 &#038;&#038; !is_array($this->value)) 
					$this->value = substr($this->value, 0, $this->maxlen);
				return $this->$name = $this->value;
			}
		}
	}


	/**
	 * Переводит в глобальную область видимости все отфильтрованные переменные
	 *
	 */
	public function globalize(){
		$slice = array_keys(array_slice((array)$this, 5));
		$args = func_num_args() ? array_intersect(func_get_args(), $slice) : $slice;
		foreach ($args as $key)
			$GLOBALS[$key] = !isset($GLOBALS[$key]) ? $this->$key : $GLOBALS[$key];
	}


	/**
	 * Возвращает имена всех отфильтрованных переменных
	 *
	 * @return array
	 */
	public function getnames(){
		return array_keys(array_slice((array)$this, 5));
	}


	/**
	 * Получает все доступные переменные из указанного источника
	 *
	 * @param string|array $source
	 * @return unknown
	 */
	public function getall($source='R'){
		$_SOURCE =&#038; $this->source($source);
		$names = array_keys($_SOURCE);
		foreach ($names as &#038;$name) {
			$type = is_array($_SOURCE[$name]) ? 'ARR' : $this->mode ;
			$name = $this->define($name, $type, $source, 0);
		}
		return $names;
	}


	/**
	 * Устанавливает режим фильтрации по умолчанию 
	 *
	 * @param string $mode
	 */
	public function setmode($mode){
		$this->mode = $mode;
	}


	/**
	 * Устанавливает щит
	 *
	 * @param boolean $mode
	 */
	public function setshield($mode){


		$this->shield = $mode;
	}


	/**
	 * Уничтожает все отфильтрованные переменные
	 *
	 */
	public function undefine(){
		$slice = array_keys(array_slice((array)$this, 5));
		$args = func_num_args() ? array_intersect(func_get_args(), $slice) : $slice;
		foreach ($args as $name)
			unset($this->$name);
	}


	/**
	 * Устанавливает, какого именно типа переменная
	 *
	 * @param string $type
	 * @param mixed $value
	 */
	private function type($type, &#038;$value){
		$value = $this->quotes &#038;&#038; !is_array($value) ? stripcslashes($value) : $value;


		if(is_array($value) &#038;&#038; $type!='ARR')
			$this->log($type,$value);
		else 
			$value = $this->quotes ? stripcslashes($value) : $value;


		if(method_exists($this,"_is_".$type))
			$this->{"_is_".$type}($value);
		else
			$this->value = $this->test($type,$value);
	}


	/**
	 * Выбирает источник переменной
	 *
	 * @param string $source
	 * @param string $name
	 * @return array
	 */
	private function &#038; source($source,$name){
		$_source = is_string($source) ? strtoupper($source) : 'default';
		switch ($_source){
			case 'R': case 'REQUEST':	return $_REQUEST; break;
			case 'P': case 'POST':		return $_POST; break;
			case 'G': case 'GET':		return $_GET; break;
			case 'C': case 'COOKIE':	return $_COOKIE; break;
			case 'F': case 'FILES':		return $_FILES; break;
			case 'ENV':		return $_ENV; break;
			case 'SERVER':	return $_SERVER; break;
			case 'SESSION':	return $_SESSION; break;
			case 'GLOGALS':	return $GLOBALS; break;
			default: $a = array($name=>$source); return $a; break;
		}
	}


	/**
	 * Бросает исключение, если переменная оказалась не предполагаемого типа
	 *
	 * @param string $regexp
	 * @param string $value
	 * @param mixed $return
	 * @return mixed
	 */
	private function log($regexp, $value, $return=null){
		if ($this->shield) 
			throw new Exception("Request: unexpected type of variable '{$value}' expected '{$regexp}'");
		return $return;
	}


	/**
	 * Проверяет строку на соответствие регулярному выражению
	 *
	 * @param string $regexp
	 * @param string $value
	 * @param mixed $return
	 * @return mixed
	 */
	private function test($regexp, $value, $return=null){
		return preg_match($regexp, $value) ? $value : $this->log($regexp, $value, $return);
	}


	/* числовые */
	private function _is_INT($value){
		$this->value = $this->test('/^[0-9]+$/', $value);
	}
	private function _is_NUM($value){
		$this->value = $this->test('/^-?([0-9]+)(.[0-9]+)?$/', $value);
	}


	/* строчные */
	protected function _is_HEX($value){
		$this->value = $this->test('/^[a-f0-9]+$/i', $value);
	}
	private function _is_LIT($value){
		$this->value = $this->test('/^[a-z]+$/i', $value);
	}
	private function _is_ALP($value){
		$this->value = $this->test('/^[a-z-_]+$/i', $value);
	}
	private function _is_ALN($value){
		$this->value = $this->test('/^[a-z0-9-_]+$/i', $value);
	}
	protected function _is_RUS($value){
		$this->value = $this->test('/^[а-яё0-9-_]+$/i', $value);
	}
	protected function _is_UKR($value){
		$this->value = $this->test('/^[а-яєїіґ-_]+$/i', $value);
	}


	/* шаблонные */
	private function _is_EML($value){
		$this->value = $this->test('/^[_a-z0-9-.]+@[a-z0-9-]+(.[a-z0-9-]{2,})+$/', $value);
	}
	private function _is_URL($value){
		$this->value = $this->test('/(ht|f)tp(s)?://(www.)?([a-z][.a-z0-9_-]+)(:[0-9]+)?/([^?]+)???([^#]+)?(#.*)?$/', $value);
	}


	/* булевые */
	private function _is_BOL($value){
		$this->value = ($value===TRUE || $value==1 || in_array($value, array('on','ON','true','TRUE','yes','YES'))) ? TRUE : $this->log($value, 'BOL', false);
	}


	/* заменяющие */
	private function _is_HTM($value){
		$this->value = $value;
	}


	private function _is_SLU($value){
		$this->value = str_replace(array("\",""","'","(",")","%","&lt;","&gt;","{","}","/","&#038;","+"), '', $value);
	}
	private function _is_TXT($value){
		$this->value = htmlspecialchars($value, ENT_QUOTES);
	}


	/* массив */
	private function _is_ARR($value){
		if (is_array($value)){
			$tmp = $value;
			foreach ($tmp AS $k => &#038;$v){
				$value = $this->quotes &#038;&#038; !is_array($v) ? stripcslashes($v) : $v;
				if (is_array($value)) 
					$this->_is_ARR($value);
				else 
					$this->{"_is_".$this->mode}($value);
				$tmp[$k] = $this->value;
			}
			$this->value = $tmp;
		}else
			$this->value = $this->log($value,'ARR');
	}


	public function __destruct(){


	}
}



</code>
</pre>
<p>Я думаю, я уже достаточно рассказал, теперь надо бы показать. Поскольку Я не могу тут реально использовать POST и GET запросы, поэтому я буду имитировать их в коде при помощи обычного массива. Итак, задача первая: получение данных из суперглобальных массивов по шаблону</p>
<pre>
<code class="php">

// создаем новый экземпляр класса
$gpc = new Request();


/*
имитируем $_GET запрос
при этом url должен выглядеть вот так
index.php?string=x_y_z&#038;int=100&#038;num=0.10&#038;hex=FACE8D
*/
$_GET = array ( 
	'string' => 'x_y_z',
	'int' => '100', 
	'num' => '0.10', 
	'hex' => 'FACE8D', 
);


/* получаем данные */
// строчный: алфавитные символы от a до z , тире - и подчерк _
$gpc->define('string','ALP','G');
// целые числа: от 0 до 9
$gpc->define('int','INT','G');
// числовые: содержащие в себе точку
$gpc->define('num','NUM','G');
// 16тиричные цыфры: от 1 до 0 и от a до f
$gpc->define('hex','HEX','G');


/*
Теперь попробуем получить сразу несколько переменных из куков
для этого имитируем массив $_COOKIE
var1=first&#038;var2=second&#038;var3=third&#038;var4=fourth
*/


$_COOKIE = array ( 
	'var1' => 'first', 
	'var2' => 'second', 
	'var3' => 'third', 
	'var4' => 'fourth', 
);


// все полученные переменные будут содержать только латинские буквы от a до z
$gpc->define(array('var1','var2','var3','var4'),'LIT','C');


/*
И последний пример из этой серии - получение массива из массива $_POST
array[1]=on&#038;array[2]=off&#038;array[3]=no&#038;array[4]=yes
*/


$_POST = array( 
	'array' => array ( 
		1 => 'on', 
		2 => 'off', 
		3 => 'no',
		4 => 'yes'
	)
);


// все переменные у нас будут булевы, поэтому мы выставляем фильтрование по умолчанию булевым
$gpc->setmode('BOL');
// дальше все как обычно, только указываем, что хотим получить массив
$gpc->define('array','ARR','P');



</code>
</pre>
<p>Надо заметить что для суперглобальных массивов таких как $_POST, $_GET, $_COOKIE, $_FILES и $_REQUEST можно указывать только первую букву (G,P,C,F,R) имена остальных $_ENV, $_SERVER, $_SESSION и $GLOBALS надо писать полностью. Но если вам не нужно использование этих массивов то вы вполне можете передать вместо них переменную, которую вы хотите провалидировать</p>
<pre>
<code class="php">

$gpc->define('eml','EML','CTAPbIuMABP@gmail.com');
$gpc->define('url','URL','http://mabp.kiev.ua/');

</code>
</pre>
<p>Так же если вас не устраивает набор стандартных правил вы можете написать вместо названия правила регулярное выражение</p>
<pre>
<code class="php">

// правило валидации пользователей на gmail.com
$gpc->define('email','/^[a-z0-9.]+@gmail.com$/i','CTAPbIuMABP@gmail.com');

</code>
</pre>
<p>Дополнительные функции. При помощи этих функция вы можете сэкономить код и время, но если честно я ими никогда не пользовался. Первая функция - getall пытается получить все доступные переменные из указанного суперглобального массива (и переданной переменной) в соответствии правилу фильтрации по умолчанию. Вторая функция - globalize переводит все отфильтрованные переменные в глобальную область видимости, а точнее делает их частью массива $GLOBALS. Следующая функция - getnames возвращает массив имен всех провалидированных переменных. И, наконец, последняя функция undefine убирает из объекта провалидированные переменные все или только те, что переданы в качестве параметров.</p>
<pre>
<code class="php">

// перевели в глобальную область видимости 4 переменные
$gpc->globalize('string','int','num','hex');


// и удалили их из контекста объекта
$gpc->undefine('string','int','num','hex');


// получили имена всех оставшихся переменных
$names = $gpc->getnames();


// применение getall возможно, если заранее известно что, например, через массив $_GET придут только числовые значения
$_GET = array ( 
	'one' => 1,
	'two' => 2, 
	'three' => 3, 
	'four' => 4, 
);
$gpc->setmode('INT');
$gpc->getall('G');

</code>
</pre>
<p>Использование щита. Если вы хотите чтобы когда переменная не проходит валидацию бросалось исключение то включите щит ($gpc->setshield(true);) это бывает полезно при дебаге когда нужно видеть какие значения приходят от того или иного запроса.</p>
<br />
]]></content:encoded>
			<wfw:commentRss>http://mabp.kiev.ua/2008/04/20/request/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Cache Manager</title>
		<link>http://mabp.kiev.ua/2008/04/16/cache_manager/</link>
		<comments>http://mabp.kiev.ua/2008/04/16/cache_manager/#comments</comments>
		<pubDate>Wed, 16 Apr 2008 21:55:59 +0000</pubDate>
		<dc:creator>CTAPbIu_MABP</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Программирование]]></category>
		<category><![CDATA[regex]]></category>

		<guid isPermaLink="false">http://mabp.localhost/?p=6</guid>
		<description><![CDATA[Я почему-то думал, что давно уже выложил в блоге свои классы опубликованные на phpclasses.org, а когда недавно хотел посмотреть один из них, оказалось, что их нет. А вот сейчас я собираюсь исправить этот недосмотр и начну с класса для кэширования страниц.


Это мой любимый класс, я очень много раз его переписывал и переделывал, особенно функцию замены [...]]]></description>
			<content:encoded><![CDATA[<p>Я почему-то думал, что давно уже выложил в блоге свои классы опубликованные на <a rel="nofollow" href="http://www.phpclasses.org/browse/author/366148.html">phpclasses.org</a>, а когда недавно хотел посмотреть один из них, оказалось, что их нет. А вот сейчас я собираюсь исправить этот недосмотр и начну с класса для кэширования страниц.</p>
<span id="more-6">
</span>
<p>Это мой любимый класс, я очень много раз его переписывал и переделывал, особенно функцию замены ссылок на странице. Итак код, а комментарии потом.</p>
<pre>
<code class="php">

class cache {
	/**
	 * @author CTAPbIu_MABP
	 * @version 1.4
	 * @license GNU General Public License
	 *
	 */


	protected $cache = NULL;
	protected $handler = array();


	/**
	 * Стартует кеширование с makeGZip(),
	 * если у браузера присутствует соотвецтвующий заголовок
	 *
	 * @param bool $gzip
	 */
	public function __construct($gzip=TRUE){
		//принимает ли браузер сжатие?
		if (@strpos($_SERVER['HTTP_ACCEPT_ENCODING'],'gzip')!==false &amp;&amp; $gzip) // @ отключает NOTICE если заголовок HTTP_ACCEPT_ENCODING не пришел вообще
			// второй параметр это степень буфферизации 0 &gt; 9
			$this-&gt;start('makeGZip', array(5));
	}


	/**
	 * Начинает новую буферизацию и записывает ее обработчик
	 *
	 * @param string $func
	 * @param array $argv
	 */
	public function start($func, $argv=NULL){
		@ob_start();
		// notice: надо передавать именно NULL, а не FALSE тогда при array_merge элемент удалится
		$this-&gt;handler[] = array($func, $argv);
	}


	/**
	 * Очищает буфер $loop раз и выталкивает последние $loop обработчиков
	 *
	 * @param int $loop
	 */
	public function free($loop=0){
		$loop = $loop ? $loop : count($this-&gt;handler);
		for($i=0;$i&lt; =$loop;$i++){
			@ob_end_clean();
			array_pop($this-&gt;handler);
		}
	}


	/**
	 * Парсит последние $loop буфферов
	 *
	 * @param integer $loop
	 * @return mixed
	 */
	public function flush($loop=0){
		$loop = $loop ? $loop : count($this-&gt;handler);
		for ($i=$loop-1;$i&gt;=0;$i--){
			// узнаем номер последнего хендлера
			$x = count($this-&gt;handler)-1;
			// получаем последний буффер для работы
			$this-&gt;cache = @ob_get_contents();
			// создаем правильный массив параметров
			$params = array_merge((array)$this-&gt;cache, (array)$this-&gt;handler[$x][1]);
			// проверяем принадлежит ли функция объекту или она пользовательская
			$handler = method_exists($this,$this-&gt;handler[$x][0]) ? array($this,$this-&gt;handler[$x][0]) : $this-&gt;handler[$x][0];
			// вызываем нужную функцию с параметрами
			$this-&gt;cache = call_user_func_array($handler, $params);
			// удаляем последний. отработаный, элемент массива
			array_pop($this-&gt;handler);
			// отключаем буферизацию
			@ob_end_clean();
			// выбрасываем назад содержимое буффера
			echo $this-&gt;cache;
		}


		return $this-&gt;cache;
	}


	/**
	 * Gzip'ирует буффер и возвращает в поток или в файл,
	 * если имя файла и расширение указано
	 *
	 * @param mixed $buf
	 * @param integer $ratio
	 * @param string $name
	 * @param string $extention
	 * @return mixed
	 */
	private function &amp; makeGZip(&amp;$buf, $ratio=0, $name='', $extention=''){
		if ($ratio === 0) return $buf;
		$bufziped = gzcompress($buf, $ratio);
		$bufziped = pack('cccccccc',0x1f,0x8b,0x08,0x00,0x00,0x00,0x00,0x00)
        	.substr($bufziped, 0, -4)
        	.pack('V',crc32($buf))
        	.pack('V',strlen($buf));
        header('Content-Encoding: gzip');
        if ($name &amp;&amp; $extention){
        	header('Content-description: File Transfer');
        	header('Content-type: application/x-gzip');
        	header('Content-length: '.strlen($bufziped));
        	header('Content-Disposition: attachment; filename='.$name.'.'.$extention.'.gz');
        }
		return $bufziped;
	}


	/**
	 * Парсит буффер в поисках ссылок и заменяет их
	 *
	 * @param mixed $buf
	 * @return mixed
	 */
	private function &amp; makeURL(&amp;$buf){
		$search = "~([actionhrefsrclocationbackground]) = [\"|'] /? ([/.a-z0-9_-]+) . (w+) ?? (S*?)? (#[^'\"]*)? [\"|']~six";
		$replace = array($this, "_makeURL");
		return preg_replace_callback($search, $replace, $buf);
	}


	/**
	 * Пересобирает ссылки из полученного массива call_back_func
	 *
	 * @return string
	 */
	private final function _makeURL($url){
		$string  = $url[1]."="http://".$_SERVER['SERVER_NAME'];
		$string .= $_SERVER['SERVER_PORT']!= 80 ? ":".$_SERVER['SERVER_PORT']."/" : "/";
		$string .= ($url[2]!="index") ? $url[2] : "";
		$string .= ($url[3]!="php") ? ".".$url[3] : (($url[2]!="index") ? "/" : "");
		parse_str($url[4],$query);
		foreach ($query as $val)
			$string .= $val ? $val."/" : "";
		$string .= $url[5]."\"";


		return $string;
	}


	/**
	 * Подсвечивает текст
	 *
	 * @param mixed $buf
	 * @param array|string $matches
	 * @param string $tag
	 * @param string $color
	 * @return mixed
	 */
	private function &amp; makeHighlight(&amp;$buf, $matches, $tag = 'b', $color = 'ffff00'){
		if (!$matches) return $buf;
		$matches = (array)$matches;
		foreach ($matches as $match)
			if($match)
				$array[] = preg_quote($match);
		if (!$array) return $buf;
		return preg_replace('#(?!&lt;.*)(?&lt;!w)('.implode('|',$array).')(?!w|[^&lt;&gt;]*&gt;)#i', '&lt;'.$tag.' style="background-color:#'.$color.'"&gt;1&lt;/'.$tag.'&gt;', $buf);
	}


	/**
	 * парсит и выводит буфер
	 *
	 */
	public function __destruct(){
		$this-&gt;flush();
	}
}

</code>
</pre>
<p>Из исходного кода видно что класс помимо разруливания буферизации и обработки буфера callback функциями имеет три базовые метода для обработки страницы.</p>
<p>Первый из них это gzip сжатие. Оно включается по умолчанию при создании класса, если пользователь прислал соответствующий заголовок в запросе, это сделано, потому что нельзя сжать только половину страницы, а остальное оставить как есть. Сам алгоритм сжатия прост как три копейки и тысячу раз описан в интернете, а заголовки посылаються автоматически. Приведу маленький пример использования:</p>
<pre>
<code class="php">

$cach = new cache();
echo "Hello World!";
$cach-&gt;flush();

</code>
</pre>
<p>Этот кусок кода вернет браузеру всем уже порядком надоевшую gzip-ированую строку "Hello World!". Если же нужно вернуть не html страницу а например файл, то пример придется немного переделать.</p>
<pre>
<code class="php">

$cache = new cache(false);
$cache-&gt;start("makeGZip", array(5,"file","txt"));
echo "Hello World!";
$cach-&gt;flush();

</code>
</pre>
<p>Надо заметить что функция $cache-&gt;start() начинает кэширование с выводом в файл. При этом она принимает параметрами имя callback функции и массив ее параметров: степень сжатия, имя файла и его расширение. В результате мы получим файл file.txt.gz, с все той же надоевшей надписью про "Хэлоу Ворлд".</p>
<p>
<s>Все страницы этого сайта в том числе и <a href="http://mabp.kiev.ua/xml/rss/">rss-поток новостей</a> сжаты этой функцией, а реальный пример сжатия в файл можно посмотреть на <a href="http://mabp.kiev.ua/xml/gsm/">Google Site Map</a> для сайта.</s>
</p>
<p>Второй идет функция для переписывания ссылок в человекочитаемую форму, например: "/page.php?foo=bar" превратится в "example.com/page/bar/". Я долгое время искал оптимальный вариант регулярного выражения для замены ссылок, придумывая самые разные комбинации, которые бы могли покрыть все виды ссылок, как например "/file.php?foo[0]=bar".</p>
<pre>
<code class="php">

$search = "~(action|href|src|location|background)=(\"|') (/)? ([/.a-z0-9_-]+) .(w+) ?? (?: (w+) = (w+?))? (?: &amp; (w+) = (w+?))? (?: &amp; (S*?))? (#[-a-zа-я0-9_ ]*)?(\"|')~six";
$search = "~(action|href|src|location|background)=(\"|') (/)? ([/.a-z0-9_-]+) .(w+) ?? (?: ([a-z0-9[]]+) = (w+?))? (?: &amp; ([a-z0-9[]]+) = (w+?))? (?: &amp; (S*?))? (#[-a-zа-я0-9_ ]*)?(\"|')~six";
$search = "~(action|href|src|location|background)=(\"|') (/)? ([/.a-z0-9_-]+) .(w+) ?? (?: ([a-z0-9[]]+) = (w+?))? (?: &amp; ([a-z0-9[]]+) = (w+?) (?: &amp; ([a-z0-9[]]+) = (w+?) (?: &amp; ([a-z0-9[]]+) = (w+?) (?: &amp; ([a-z0-9[]]+) = (w+?)?)?)?)?)? (#[-a-zа-я0-9_ ]*)?(\"|')~six";

</code>
</pre>
<p>Но все они были недостаточно хороши, одни не покрывали массивы, другие могли распарсить ограниченное количество пар key=value в query string, а третьи были очень медлительны. А потом я решил, что занимаюсь не тем, регулярки не должны парсить урлы, они должны их только находить! и я решил переложить все на call-back функцию, в результате чего получился вот такой код, который был размазан для удобочитаемости</p>
<pre>
<code class="php">

private function &amp; makeURL(&amp;$buf){
	return preg_replace_callback("~([actionhrefsrclocationbackground]) = [\"|'] /? ([/.a-z0-9_-]+) . (w+) ?? (S*?)? (#[^'\"]*)? [\"|']~six", array($this, "_makeURL"), $buf);
}

</code>
</pre>
<p>Я думаю надо объяснить эту функцию на примере, так как все мои знакомые программисты не смогли понять ее смысла и красоты. Функция ищет внутренние ссылки и отравляет результат другой функции, которая собственно над ними издевается, как хочет. Вторая функция принимает массив из 5 элементов. Попробую описать это таблицей на примере ссылки <strong>&lt;a href = "/page.php?name=foo&amp;param[0]=bar#anchor"&gt;link&lt;/a&gt;</strong> и картинки <strong>&lt;img src = "/path/to/image.pic.jpg"&gt;</strong>
</p>
<table style="border-collapse: collapse;" border="1">
<tbody>
<tr>
<th>№</th>
<th>Патерн</th>
<th>Link</th>
<th>Image</th>
</tr>
<tr>
<td>1</td>
<td>([actionhrefsrclocationbackground])</td>
<td>href</td>
<td>src</td>
</tr>
<tr>
<td>2</td>
<td>([/.a-z0-9_-]+)</td>
<td>page</td>
<td>/path/to/image.pic</td>
</tr>
<tr>
<td>3</td>
<td>(w+)</td>
<td>php</td>
<td>jpg</td>
</tr>
<tr>
<td>4</td>
<td>(S*?)</td>
<td>name=foo&amp;param[0]=bar</td>
<td>
</td>
</tr>
<tr>
<td>5</td>
<td>(#[^'"]*)</td>
<td>#anchor</td>
<td>
</td>
</tr>
</tbody>
</table>
<p>Тут есть одно замечание - <strong>actionhrefsrclocationbackground</strong> на самом деле не что иное как описание местонахождения ссылки <em>action, href, src, location, background</em>, все это можно было бы написать через палку <strong>|</strong> но так работает быстрее. Более того если убрать action то он все равно будет заменяться так как слово location содержит все буквы слова action. Учитывая, что повторяющиеся буквы можно убрать и поставить в алфавитном порядке <strong>abcdefghiklnorstu</strong> все равно будет работать, но удобочитаемость пропадет напрочь!</p>
<p>Функция _makeURL получает массив и начинает его склеивать в нужном порядке, самую большую ценность тут представляет парсинг query string и его склейку через слеш, собственно то из-за чего все и затевалось. Можно склеивать не только через слеш и приводить к виду директории, а например приводить к виду "page/bar.html"</p>
<p>В результате получаем <strong>&lt;a href="http://example.com:8080/page/foo/bar#anchor"&gt;link&lt;/a&gt;</strong> и <strong>&lt;img src="http://example.com:8080/path/to/image.pic.jpg"&gt;</strong>
</p>
<p>Еще одна маленькая деталь для того чтобы все это работало нужно написать правила в .htaccess по приведению ссылок в нормальный вид, тут уже я не в силах помочь, каждый должен будет сам для себя  писать, единственное могу показать как он выглядит для моего сайта</p>
<pre>
<code class="no-highlight">

#rewrite engine
Options FollowSymLinks -Indexes -Multiviews
RewriteEngine on
RewriteBase /
#RegExp have only 9 back-references
RewriteRule ^(content)(/([0-9]+)(/([0-9]+)(/([0-9]+)(/([a-z_]+))?)?)?)?/?$					index.php?act=$1&amp;year=$3&amp;month=$5&amp;day=$7&amp;name=$9	[NC,L]
RewriteRule ^(content)(/([a-z0-9_-]+)(/([a-z_]+))?)?/?$										index.php?act=$1&amp;cat=$3&amp;name=$5						[NC,L]
RewriteRule ^(user)(/([a-z0-9_-]+)(/([a-z0-9_-]+)(/([a-z0-9_-]+)(/([a-z0-9_-]+))?)?)?)?/?$	index.php?act=$1&amp;name=$3							[NC,L]
RewriteRule ^(message)(/([a-z0-9_-]+))?/?$													index.php?act=$1&amp;msg=$3								[NC,L]
RewriteRule ^(xml)(/([a-z]+)(/([a-z0-9_-]+))?)?/?$											shell.php?act=$1&amp;type=$3&amp;name=$5					[NC,L]
RewriteRule ^(plugins)(/([a-z]+)(/([a-z]+))?)?/?$											shell.php?act=$1&amp;name=$3∂=$5					[NC,L]

</code>
</pre>
<p>Ну и наконец третья функция, она служит для подсветки слов в тексте. Честно признаюсь, регулярное выражение для нее я нарыл в интернете. Функция подсвечивает слова на странице, причем следит, чтобы эти слова не были частью html кода. Приведу пример:</p>
<pre>
<code class="php">

$cache = new cache();
$cache-&gt;start("makeHighlight",array(array('class','div'),"i"));
echo "&lt;div class='highlighted'&gt;this div has class 'highlighted'&lt;/div&gt;";

</code>
</pre>
<br />
В результате получим вот такой html код, естественно сжатый gzip'ом, его же никто не отменял<br />
<pre>
<code class="html">

&lt;div class='highlighted'&gt;this &lt;i style="background-color:#ffff00"&gt;div&lt;/i&gt; has &lt;i style="background-color:#ffff00"&gt;class&lt;/i&gt; 'highlighted'&lt;/div&gt;

</code>
</pre>
<br />
Но это плохой пример, можно смастерить что-то более правдоподобное<br />
<pre>
<code class="php">

$cache = new cache();
$url = parse_url($_SERVER['HTTP_REFERER']);
if (strpos($url['host'],'google') !== false){
	parse_str($url['query'],$query);
	$cache-&gt;start("makeHighlight",array(explode(' ',$query['q'])));
}

</code>
</pre>
<p>Если на ваш сайт перейдут с гугла, этот код подсветит на странице слова из поискового запроса. <s>Посмотреть, как в реальности работает такой код, можно перейдя с <a rel="nofollow" href="http://www.google.com/search?q=site%3Amabp.kiev.ua+jQuery">Google</a> по любой ссылке, слово jQuery должно быть, выделено жиром и подсвечено желтым</s>
</p>
<p>И на последок приведу пример как вставить в класс свою функцию обработки текста, например вы хотите заменять строки по словарю и у вас есть два массива $search и $replace. Попробуем написать простенькую функцию simle_replace которая это будет делать.</p>
<pre>
<code class="php">

$cache = new cache();
$search = array("CSS","PHP","JS");
$replace = array("&lt;acronym title='Cascading Style Sheets'&gt;CSS&lt;/acronym&gt;",
		 "&lt;acronym title='PHP Hypertext Preprocessor'&gt;PHP&lt;/acronym&gt;",
		 "&lt;acronym title='JavaScript'&gt;JS&lt;/acronym&gt;",
		);
// $buf is always first argument
function &amp; simle_replace(&amp;$buf,$search,$replace){
	return str_replace($search,$replace,$buf);
}


$cache-&gt;start("simle_replace",array($search,$replace));

</code>
</pre>
<br />
Как видите ничего сложного! Приятной работы!]]></content:encoded>
			<wfw:commentRss>http://mabp.kiev.ua/2008/04/16/cache_manager/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
