Skip to content

Instantly share code, notes, and snippets.

@MihanEntalpo
Created October 31, 2014 15:20
Show Gist options
  • Save MihanEntalpo/cd4d13ecd049003143e7 to your computer and use it in GitHub Desktop.
Save MihanEntalpo/cd4d13ecd049003143e7 to your computer and use it in GitHub Desktop.
H.php из путевого
<?php
/**
* Класс-хелпер для множества разных полезных функций. Название выбрано так, чтобы пользоваться можно было максимально быстро
*/
class H
{
/**
* Необязательный запуск чего-либо
* @param Closure $func
* @return \Exception
*/
public static function notNeccesary($func)
{
try
{
$result = $func();
return $result;
} catch (Exception $ex) {
$exception = $ex;
return $ex;
}
}
public static function checkbox($name, $default=true, $post=true)
{
$val = null;
if (!H::post())
{
if (H::session($name)==='on')
{
$val = true;
}
else if (H::session($name)==='off')
{
$val = false;
}
else
{
$val = true;
}
}
else
{
if (is_null(H::post($name,null)))
{
$val = false;
}
else
{
$val = true;
}
H::session($name, $val ? 'on' : 'off');
}
return $val;
}
/**
* Преобразование из CamelCase в раделенные подчеркиваниями части слова
* TextPage -> text_page, someBigAndLongName -> some_big_and_long_name
* @param string $name исходное имя
* @return string преобразованное имя
*/
public static function fromCamelCase($name)
{
$part = "";
$parts = array();
for($i=0;$i<mb_strlen($name,"UTF-8");$i++)
{
$l = mb_substr($name,$i,1,"UTF-8");
if (preg_match('#[A-Z]#',$l))
{
if ($part)
{
$parts[] = $part;
$part = "";
}
$part .= lcfirst($l);
}
else
{
$part .= $l;
}
}
if ($part) $parts[] = $part;
return implode("_" , $parts);
}
/**
* Преобразует запятые в точки
* @param string $src
* @return string
*/
public static function commaToDot($src)
{
return str_replace(",",".",$src);
}
/**
* Функция обрезающая длинный текст до определенного количества символов
* и, если надо, вывыодящая общее количество символов
* @param string $text исходный текст
* @param integer $maxLength максимальное количество символов
* @param boolean $showFullCount показывать полное количество?
*/
public static function cutLong($text,$maxLength,$showFullCount)
{
$len = mb_strlen($text,"UTF-8");
if ($len<=$maxLength)
{
$res = $text;
}
else
{
$res = mb_substr($text,0,$maxLength,"UTF-8") . "...";
if ($showFullCount) $res .= "(всего " . $len . " симв.)";
}
return $res;
}
/**
* Функция эквивалент time() за тем исключением, что использует время в текущем часовом поясе сервера.
* @return type
*/
public static function time()
{
return SmartDateTime::create()->getTimestamp();
}
/**
* Проверяет, навешано ли на объект поведение опредленного класса
* @param CComponent $component что угодно на что можно навешать поведение
* @param string $behClass класс поведения
* @return boolean
*/
public static function hasBehavior(CComponent $component,$behClass)
{
$behs = $component->behaviors();
foreach($behs as $name=>$beh)
{
if (get_class($component->asa($name))==$behClass) return true;
}
return false;
}
/**
* Функция освобождает память, занятую CActiveRecord
* @param CActiveRecord $obj
*/
public static function freeAR($obj)
{
//Очищаем релейшены
$relations = $obj->relations();
foreach($relations as $k=>$v)
{
$obj->$k=null;
}
//Отключаем поведения
$obj->detachBehaviors();
//Уничтожим сам объект
$obj=null;
}
/**
* Получить значение из массива POST переданного в теле запроса с тапом данных application/json
* @param string $var имя переменной, если не задано - будет вернут весь массив
* @param mixed $default значение по умолчанию, будет возвращено, если ключа $var в массиве не найдется
* @return type
*/
public static function postJson($var=null, $default=null)
{
static $jsonPostVars = null;
if (is_null($jsonPostVars))
{
$txt = @file_get_contents('php://input');
$jsonPostVars = json_decode($txt, true);
}
return is_null($var) ? $jsonPostVars : H::gisset($jsonPostVars[$var],$default);
}
/**
* Если в $_POST пусто, а в application/json переданы какие-то данные, то они заменят собой $_POST
*/
public static function setPostJson()
{
if (!H::post() && !!H::postJson()) $_POST = H::postJson();
}
/**
* Функция возвращает массив констант указанного класса. Может отфильтровать из него только определенные
* @staticvar array $classConsts статическая переменная для кэширования констант класса на будущее
* @param string|object $className имя класса, либо объект
* @param array $onlyThisOnes массив имен констант которые нужно отобрать. Остальные будут выкинуты. Если не указан - вернется полный массив констани
* @param boolean $flipArray Использовать операцию flip_array перед выдачей массива?
* @return массив констант имя=>значение
*/
public static function getClassConsts($className,$onlyThisOnes=array(),$flipArray=false)
{
if (is_object($className)) $className = get_class($className);
static $classConsts = array();
if (!isset($classConsts[$className]))
{
$r = new ReflectionClass($className);
$consts = $r->getConstants();
$classConsts[$className] = $consts;
}
$cs = $classConsts[$className];
if (is_array($onlyThisOnes) && count($onlyThisOnes)>0)
{
$rcs = array();
foreach($onlyThisOnes as $name)
{
if (isset($cs[$name]))
{
$rcs[$name] = $cs[$name];
}
}
$cs = $rcs;
}
if ($flipArray) $cs =array_flip($cs);
return $cs;
}
/**
* Ограничить значение минимумом и максимумом, и если надо - ограничить до целых
* @param number $value Число
* @param number $min Минимум
* @param number $max Максимум
* @param boolean $integer огруглять до целых? если стоит эта опция, то сначало произойдет ограничение до min или max а потом округление в меньшую или большую сторону соответственно (чтобы уложиться внутрь лимита)
* @return number
*/
public static function limit($value,$min,$max,$integer=true)
{
if ($value > $max)
{
$value=$max;
if ($integer && !is_integer($value)) $value = floor ($value);
}
if ($value < $min)
{
$value=$min;
if ($integer && !is_integer(($value))) $value = ceil ($value);
}
return $value;
}
public static function getObjectMembers($obj, $props){
$resArr = array();
foreach($props as $oneProp){
$resArr[$oneProp] = H::objP($obj, $oneProp);
}
return $resArr;
}
/**
* Аналог функции PHP unserialize, только без нотайса и возвращающий $default если не удалось рассериализовать
* @param string $val - строка для рассериализации
* @param string $default - значение по умолчанию, если что-то пойдет не так
* @return mixed результат
*/
public static function unserialize($val, $default = null){
$res = @unserialize($val);
if(is_string($val) && strlen($val) && ($res != false)){
return $res;
}
else{
return $default;
}
}
/**
* Функция принимает массив объектов, а возвращает ObjArray
* можно использовать например так:
* $users = User::model()->findAll(); //Нашли всех юзеров
* $names = H::objArray($users)->name; //Получили массив имен пользователей
* $requests = H::objArray($users)->countRelation('requests'); //получили количества заявок для всех пользователей
* $activeUsers = H::objArray($users)->filter(function($user){return $user->is_active;})->get(); //Получили массив только активных пользователей (именно массив)
* @param type $array
*/
public static function objArray($array)
{
return ObjArray::create($array);
}
/**
* Аналог функции end(), возвращающей последний элемент массива
* возвращает ПЕРВЫЙ элемент массива
* @param array $array массив
* @param string $key - сюда будет записан ключ первого элемента
* @param mixed $default - значение которое будет возвращено, если массив пуст, или вообще не является массивом
* @return mixed первый элемент массива
*/
public static function first($array,&$key=null,$default=null)
{
if (!is_array($array)) return $default;
if (count($array)==0) return $default;
reset($array);
list($key,$value) = each($array);
reset($array);
return $value;
}
public static function isPowerOf2($number)
{
if ($number==0) return false;
if ($number != (int)$number) return false;
$l = log($number) / log(2);
if ((int)$l != round($l,5)) return false;
return true;
}
/**
* Поиск файлов - классов в заданной папке, наследованных от определенного класса (можно и не напрямую)
*
* Пример:
* $enum = H::searchClasses('application.components.schemeParamTypes' , 'SchemeParamType', function($cls) { return $cls::$typeName; });
* Возвращает массив в котором ключи - имена классов типов параметров схемы (наследников класса SchemeParamType), а значения - их человеческие названия,
* полученные из полей static $typeName классов.
*
* @param string $path где смотреть? (можно также указывать Алиас)
* @param string $parentClass как звать родительский класс?
* @param integer $cacheDuration время кэширования
* @param string $cacheSuffix добавка к имени кэша. Нужна для того, чтобы при разных функциях classProcessor можно было задавать разные ключи кэша
* @param Closure $classProcessor обработчик, которому передаётся имя класса, а он должен вернуть какое-то значение
* @return array Возвращает массив array('class1'=>'class1', 'class2'=>'class2', 'class3'=>'class3') если не передан $classProcessor. Если же передан, то
* ключи массива будут именами классов, а значения - теми значениями, которые вернул $classProcessor
*/
public static function searchClasses($path, $parentClass, $classProcessor=null, $cacheSuffix="", $cacheDuration=300)
{
$classes = array();
$cacheKey = "searchClasses[" . $parentClass . "," . md5($path) . "]." . $cacheSuffix;
if (!H::getCache($cacheKey, $classes) || 1)
{
if (is_null($classProcessor)) $classProcessor = function($cls) { return $cls; };
if (!file_exists($path))
{
$path = Yii::getPathOfAlias($path);
if (!file_exists($path))
{
throw new REX("Path, given to searchClasses doesn't exists! Even after Yii::getPathOfAlias! Here:" . $path);
}
}
$files = scandir($path);
foreach($files as $file)
{
if (preg_match("#.+\.php#i",$file))
{
$class = str_replace(".php","",$file);
require_once $path . "/" . $file;
if (class_exists($class,false))
{
if (is_subclass_of($class, $parentClass))
{
$classes[$class] = $classProcessor($class);
}
}
}
}
H::setCache($cacheKey, $classes,$cacheDuration);
}
return $classes;
}
/**
* Возвращает тоже самое что и обычный end() но только работает не по ссылке а по значению.
* Это может пригодиться когда нужно получить последний элемент из чего-то не являющегося полноценным массивом, например
* из свойства-релейшона некоей модели.
* Работает медленно, при помощи foreach !
* @param type $arr
*/
public static function end($arr)
{
$last = null;
foreach($arr as $key=>$value)
{
$last = $value;
}
return $last;
}
/**
* Выдает массив родительских классов начиная от ближайшего и заканчивая последним (это как правило StdClass)
*
* @param string|object $obj
*
* @return array массив родительских классов, ключи в котором - тоже имена классов. Чем дальше элемент -
* тем дальше этот родительский класс от данного.
*/
public static function getParentClasses ( $obj ) {
$lastClass = $obj;
$classes = array();
do
{
$lastClass = get_parent_class( $lastClass );
if ( $lastClass )
{
$classes[$lastClass] = $lastClass;
}
}
while ( $lastClass );
return $classes;
}
/**
* Вывести таблицу заполненную данными полученными из некоего SQL-запроса
* @param type $table
*/
public static function printSqlDataTable($table){
if (!is_array($table))
{
echo "\$table is not an array<br>";
return;
}
else if(!is_array(end($table)))
{
echo "\$table does not contains arrays<br>";
return;
}
$titles = array_keys(end($table));
?>
<b>Rows:<?=count($table)?></b><br>
<table>
<tr>
<?php foreach($titles as $t): ?>
<td style='border:1px solid black;'>
<?=$t?>
</td>
<?php endforeach; ?>
</tr>
<?php foreach($table as $row):?>
<tr>
<?php foreach($row as $cell): ?>
<td style='margin:0px;padding:1px;border:1px solid grey;'>
<?=$cell?>
</td>
<?php endforeach; ?>
</tr>
<?php endforeach;?>
</table>
<?php
}
/**
* Функция возвращающая хорошее описательное имя типа данных для переменной
* @param mixed $var переменная (или значение)
* @return string тип в виде хорошего названия.
* Варианты: integer, float, string, boolean, null, object of class SomeClass, array(25 elements)
*/
public static function getTypeName($var)
{
if (is_null($var)) return "NULL";
$t = gettype($var);
if ($t=='object') return "object of class '" . get_class($var) . "'";
if ($t=='double') return 'float';
if ($t=='array') return 'array (' . count($var) . " elements)";
return $t;
}
/**
* Увеличивает на единицу значение массива с соответствующим ключем. Если такого ключа еще нет - добавляет.
* @param array $array ссылка на массив
* @param mixed $key ключ
*/
public static function incArr(&$array,$key)
{
if (!isset($array[$key])) $array[$key] = 0;
$array[$key]++;
}
public static function dec2hex($num,$digits=0)
{
$hex = dechex($num);
if ($digits==0) return $hex;
if (strlen($hex)<$digits) $hex = str_repeat ('0', $digits - strlen($hex)) . $hex;
if (strlen($hex)>$digits) $hex = str_repeat('F',$digits);
return $hex;
}
/**
* Уменьшает на единицу значение массива с соответствующим ключем. Если такого ключа еще нет - добавляет значение 0 с таким ключём.
* @param array $array ссылка на массив
* @param mixed $key ключ
*/
public static function decArr(&$array,$key)
{
if (!isset($array[$key])) $array[$key] = 0;
$array[$key]--;
}
public static function debugAppendToFile($string,$filename)
{
$f = @fopen($filename,"a");
@fwrite($f, $string . "\n");
@fclose($f);
}
public static function debugStringToBase16($str)
{
$x = 0;
for ($i=0;$i<strlen($str);$i++)
{
$x .= dechex(ord(substr($str,$i,1)));
}
return $x;
}
public static function bytesToHuman($bytes,$signsAfterComma=0)
{
$names = array('KB','MB','GB','TB');
for($i=count($names)-1;$i>-1;$i--)
{
$p = pow(1024,$i+1);
if ($bytes > ($p))
{
return round($bytes/$p) ." " . $names[$i];
}
}
return $bytes . "B";
}
/**
* Функция тестирования PHP-кода
* создаёт временный файл, записывает туда код, выполняет с помощью консольного php
* во избежания торможения результат кэшируется на 5 минут
* @param string $phpCode Код, который нужно проверить
* @param string $output ссылка на переменную, куда будет записан результат работы скрипта
* @param boolean $ignoreCache не использовать кэш. Ну вдруг понадобится...
* @return boolean если всё получилось - true, иначе - false
*/
public static function testPhp($phpCode, &$output, $ignoreCache=false)
{
$cacheKey = "testPhpCache_" . md5($phpCode);
$res = array();
if ($ignoreCache || !H::getCache($cacheKey, $res,array()))
{
$code = "<?php \n" . $phpCode;
$file = tempnam(sys_get_temp_dir(), "testPhp");
file_put_contents($file,$code);
$cmd = "php -e " . $file . " 2>&1 ";
$resultLines=array();
$status = exec($cmd,$resultLines);
if (file_exists($file)) unlink($file);
$res['output'] = implode("\n", $resultLines);
$res['result'] = !!$status;
H::setCache($cacheKey, $res, 600);
}
$output = $res['output'];
return $res['result'];
}
/**
* Функция добавления элемента в начало массива перед всеми.
* Сохраняет нумерацию числовых ключен в отличии от array_merge и array_unshift
* Внимание! Тормозная! Сложность O(n)!!!!
* Если не нужно сохранять ключи - юзайте array_unshift!!!
* @param array $srcArray исходный массив
* @param mixed $prepValue Добавляемое значение
* @param string|integer $prepKey Ключ добавляемого значения
* @return type
*/
public static function array_prependSLOW($srcArray,$prepValue,$prepKey)
{
$arr = array($prepKey=>$prepValue);
foreach($srcArray as $k=>$v)
{
$arr[$k] = $v;
}
return $arr;
}
public static function tickTime($title=null)
{
static $init=null;
static $prevTime=0;
static $prevTitle="";
if (is_null($init))
{
$init = true;
$prevTitle = $title;
$prevTime = microtime(true);
}
else
{
$delta = microtime(true) - $prevTime;
return $prevTitle . ": " . $delta . " с.<br>\n";
$prevTitle = $title;
$prevTime = microtime(true);
}
return null;
}
/**
* Проверка, является ли текущий запрос GET-запросом
* @return boolean
*/
public static function isGET()
{
return Yii::app()->request->requestType=="GET";
}
/**
* Проверка, является ли текущий запрос POST-запросом
* @return boolean
*/
public static function isPOST()
{
return Yii::app()->request->requsetType=='POST';
}
/**
* Функция, удаляющая из массивов и объектов любой глубины вложенности все хранящиеся замыкания (closures)
* Это требуется для работы функции Serialize, которая, как известно, не умеет сериализовывать замыкания.
*
* @param array|object массив или объект который нужно пройти
* @param mixed $replace то, на что нужно заменить замыкание. По умолчанию это строка "instanceof Closure"
* @param integer $level текущий уровень вложенности, изначально = 0, задавать не требуется. Использовался для отладки.
*
* @return array|object возвращает обработанный объект/массив.
*/
public static function removeClosures ( $arr, $replace = "instanceof Closure", $level = 0,$dbg=false) {
static $walkedObjects = array();
if ($dbg) if ($level==0) echo "<pre>[Starting to remove closures]\n";
if($level == 0) $walkedObjects = array();
$deep = str_repeat(" ", $level);
if ( is_object( $arr ) && get_class( $arr ) == 'Closure' )
{
return $replace;
}
if ( is_array( $arr ) )
{
$fields = $arr;
}
if ( is_object( $arr ) )
{
if ( is_object( $arr ) ){
foreach($walkedObjects as &$oneObj){
if($arr === $oneObj){
return $arr;
}
}
$walkedObjects[] = $arr;
}
$fields = get_object_vars( $arr );
}
foreach ( $fields as $k => $v )
{
if ($dbg) echo $deep . "key: " . $k . "\n";
if ( is_object( $v ) && get_class( $v ) == 'Closure' )
{
if ($dbg) echo $deep . " IT'S A CLOSURE!!! REPLACING!!!\n";
$fields[$k] = $replace;
$v = $replace;
}
$ia = is_array($v);
$io = is_object($v);
if ( $ia || $io )
{
if ($dbg) echo $deep . " it's an " . ($ia ? 'array' : 'object') . ", going deeper...\n";
$fields[$k] = self::removeClosures( $v, $replace, $level + 1 ,$dbg);
}
}
if ( is_array( $arr ) )
{
$arr = $fields;
}
if ( is_object( $arr ) )
{
foreach ( $fields as $k => $v )
{
$arr->$k = $v;
}
}
if ($dbg) if ($level==0) echo "[Ending of closures remove process]</pre>";
return $arr;
}
/**
* Функция преобразующая переменную к виду, готовому для использования в foreach. Если
* переменная - не массив или вообще не определена - будет возвращен пустой массив
*
* @param array|mixed $var
*
* @return array
*/
public static function ar ( &$var ) {
if ( isset( $var ) && is_array( $var ) )
{
return $var;
}
return array();
}
/**
* Возвращает элемент массива. Удобно для работы с функциями, возвращающими массивы
* Model->findAll() - вернет массив
* H::arrayItem(Model->findAll(),0)-> получим элемент с номером 0, не сохраняя массив в промежуточную переменную
*
* @param array $arr массив
* @param mixed $key ключ
* @return mixed значение элемента
*/
public static function arrayItem ( $arr, $key , $default=null) {
if (!isset($arr[$key])) return $default;
return $arr[$key];
}
/**
* Пытается получить из объекта заданное поле, либо возвращает объект делающий тоже самое.
* Если это не объект или поля нет - будет возвращено значение $default
*
* Пример:
* <pre>
* $x = SomeModel::model()->findByPk(15);
* if (H::objP($x,'type')==5) echo "Ура, у нас запись, с типом равным пяти!";
* //Даже если запись не была получена - функция objP в худшем случае вёрнёт null
* //Если бы мы написал if ($x->type==5) - могла произойти ошибка, если бы findByPk возвратила null.
* </pre>
* Второй пример:
* <pre>
* $x = SomeModel::model()->findByPk(15);
* if (H::objP($x)->type==5) echo "Ура, у нас запись, с типом равным пяти!";
* //Здесь альтернативный синтаксис, позволяющий писать меня полей как и раньше.
* </pre>
* @param Object $var объект
* @param string $field название поля, если не передано, будет создан и возвращённ объект DummyObj
* @param mixed $default значение по умолчанию
* @param boolean $notnull если = true, то в случае если поле равно false, будет возвращено значение $default
* @return mixed значение поля или $default или объект DummyClass
*/
public static function objP ( $var, $field=null, $default = NULL, $notnull = FALSE ) {
if (is_null($field))
{
return new DummyObj($var, $default);
}
else if ( is_object( $var ) )
{
if ( isset( $var->$field ) && ( $var->$field || !$notnull ) )
{
return $var->$field;
}
}
return $default;
}
/**
* Функция, проверяющая заданность переменной, и, в зависимости от результата,
* возвращающая либо значение переменной, либо значение $default
* Внимание! При проверке ключей массивов есть сайд-эффект!
* Если ключа такого нет, то при проверке он создаётся со значением NULL.
* Например:
* $x = array(1=>'a',2=>'b');//создаст соответствующий массив
* echo gisset($x[3],'Ключ 3 не найден');//выдаст "ключ 3 не найден"
* var_export($x);//Выдаст array(1=>'a',2=>'b',3=>NULL)
* Этот эффект не влияет на дальнейшую проверку, так как проверка isset для элемента с ключем 3 и значением NULL всё равно не пройдет.
*
* @param mixed $var любая переменная
* @param mixed $default любое значение
*
* @return mixed возвращает результат операции: (isset($var)) ? $var : $default
*/
public static function gisset ( &$var, $default = FALSE ) {
return ( isset( $var ) ) ? $var : $default;
}
/**
* Аналог функции gisset предназначенная для нахождения элемента в массиве.
* В отличии от gisset лишен сайдэффекта и не создаёт элемент в массиве при проверке
* @param array $arr
* @param string $key
* @param mixed $default
*/
public static function gissetAr(&$arr, $key,$default=FALSE)
{
return isset($arr[$key]) ? $arr[$key] : $default;
}
/**
* Проходит по всем полям, и те из них, в которых записаны строки "true" или "false" переводит в двоичные значения true или false
*
* @param type $obj
*/
public static function objBool ( &$obj ) {
foreach ( $obj as $prop => &$value )
{
if ( $value === 'false' )
{
$value = FALSE;
}
else if ( $value === 'true' )
{
$value = TRUE;
}
}
}
/**
* Разворачивает имя таблицы из "{{table}}" в "prefix_table"
*
* @param string $table имя таблицы, либо любая строка, содержащая это имя.
*
* @return mixed
*/
public static function tblWithPrefix ( $table ) {
return SQL::tblWithPrefix($table);
}
/**
* Функция производит сериализацию, сжатие, кодирование и форматирование данных в "блок" - прямоугольный кусок текста
* @param mixed $var
*/
public static function serializeBlock($var){
$s = serialize($var);
$c = gzencode($s, 5);
$b = '"' . base64_encode($c) . '"';
$len = strlen($b);
$root = ceil(sqrt($len)) * 3;
$lines = array();
$pos=0;
do
{
$part = substr($b,$pos,$root);
$lines[] = $part;
$pos+= $root;
if ($len - $pos < 0.2 * $root)
{
$lines[count($lines)-1] .= substr($b,$pos,$root);
break;
}
}
while ($pos<=strlen($b));
$result = implode("\n",$lines);
return $result;
}
/**
* Функция рассериализовывает блок, полученный с помощью serializeBlock
* @param string $block
*/
public static function unserializeBlock($block)
{
$b = str_replace(array('\n','\t','\r',' ','"',"'"),"",$block);
$c = base64_decode($b);
$s = H::gzdecode($c);
$var = unserialize($s);
return $var;
}
public static function print_pre ( $data, $return = FALSE ) {
$txt = "<pre>" . print_r( $data, TRUE ) . "</pre>";
if ( $return )
{
return $txt;
}
echo $txt;
}
/**
* Функция разжатия gzip-строки
* @author katzlbtjunk@hotmail.com
* @param string $data
* @param string $filename
* @param string $error
* @param integer $maxlength
* @return null|boolean|string
*/
public static function gzdecode($data,&$filename='',&$error='',$maxlength=null)
{
$len = strlen($data);
if ($len < 18 || strcmp(substr($data,0,2),"\x1f\x8b")) {
$error = "Not in GZIP format.";
return null; // Not GZIP format (See RFC 1952)
}
$method = ord(substr($data,2,1)); // Compression method
$flags = ord(substr($data,3,1)); // Flags
if ($flags & 31 != $flags) {
$error = "Reserved bits not allowed.";
return null;
}
// NOTE: $mtime may be negative (PHP integer limitations)
$mtime = unpack("V", substr($data,4,4));
$mtime = $mtime[1];
$xfl = substr($data,8,1);
$os = substr($data,8,1);
$headerlen = 10;
$extralen = 0;
$extra = "";
if ($flags & 4) {
// 2-byte length prefixed EXTRA data in header
if ($len - $headerlen - 2 < 8) {
return false; // invalid
}
$extralen = unpack("v",substr($data,8,2));
$extralen = $extralen[1];
if ($len - $headerlen - 2 - $extralen < 8) {
return false; // invalid
}
$extra = substr($data,10,$extralen);
$headerlen += 2 + $extralen;
}
$filenamelen = 0;
$filename = "";
if ($flags & 8) {
// C-style string
if ($len - $headerlen - 1 < 8) {
return false; // invalid
}
$filenamelen = strpos(substr($data,$headerlen),chr(0));
if ($filenamelen === false || $len - $headerlen - $filenamelen - 1 < 8) {
return false; // invalid
}
$filename = substr($data,$headerlen,$filenamelen);
$headerlen += $filenamelen + 1;
}
$commentlen = 0;
$comment = "";
if ($flags & 16) {
// C-style string COMMENT data in header
if ($len - $headerlen - 1 < 8) {
return false; // invalid
}
$commentlen = strpos(substr($data,$headerlen),chr(0));
if ($commentlen === false || $len - $headerlen - $commentlen - 1 < 8) {
return false; // Invalid header format
}
$comment = substr($data,$headerlen,$commentlen);
$headerlen += $commentlen + 1;
}
$headercrc = "";
if ($flags & 2) {
// 2-bytes (lowest order) of CRC32 on header present
if ($len - $headerlen - 2 < 8) {
return false; // invalid
}
$calccrc = crc32(substr($data,0,$headerlen)) & 0xffff;
$headercrc = unpack("v", substr($data,$headerlen,2));
$headercrc = $headercrc[1];
if ($headercrc != $calccrc) {
$error = "Header checksum failed.";
return false; // Bad header CRC
}
$headerlen += 2;
}
// GZIP FOOTER
$datacrc = unpack("V",substr($data,-8,4));
$datacrc = sprintf('%u',$datacrc[1] & 0xFFFFFFFF);
$isize = unpack("V",substr($data,-4));
$isize = $isize[1];
// decompression:
$bodylen = $len-$headerlen-8;
if ($bodylen < 1) {
// IMPLEMENTATION BUG!
return null;
}
$body = substr($data,$headerlen,$bodylen);
$data = "";
if ($bodylen > 0) {
switch ($method) {
case 8:
// Currently the only supported compression method:
$data = gzinflate($body,$maxlength);
break;
default:
$error = "Unknown compression method.";
return false;
}
} // zero-byte body content is allowed
// Verifiy CRC32
$crc = sprintf("%u",crc32($data));
$crcOK = $crc == $datacrc;
$lenOK = $isize == strlen($data);
if (!$lenOK || !$crcOK) {
$error = ( $lenOK ? '' : 'Length check FAILED. ') . ( $crcOK ? '' : 'Checksum FAILED.');
return false;
}
return $data;
}
public static function formatSeconds($seconds)
{
$seconds = (int)$seconds;
if ($seconds < 10)
{
return "0" . $seconds;
}
else if($seconds < 60)
{
return $seconds;
}
else if($seconds < 3600)
{
$minutes = H::formatSeconds((int) ($seconds / 60));
return $minutes . ":" . H::formatSeconds($seconds % 60);
}
else
{
$minutes = H::formatSeconds((int) ($seconds / 60));
$hours = H::formatSeconds((int)$minutes / 60);
return $hours . ":" . $minutes . ":" . ($seconds - ($seconds % 60));
}
}
/**
* Берет ключ из последнего элемента массива, удаляет его и вставлет его же в конец массива в качестве значения.
* Это нужно для формирования безссылочного пункта breadCrumbs, создаваемого стандартным виджетом.
*
* @param array $arr исходный массив
*
* @return array
*/
public static function unkeyLastItem ( $arr ) {
$arr2 = array();
$num = count( $arr );
$i = 0;
foreach ( $arr as $key => $value )
{
$i++;
if ( $i == $num )
{
$lastKey = $key;
$arr2[] = $key;
break;
}
else
{
$arr2[$key] = $value;
}
}
return $arr2;
}
/**
* Функция выполняет переданную ей функцию и возвращает то что перехвачено из буфера вывода функции
* @param callable $fn
*
* @return string
*/
public static function ob ( $fn ) {
ob_start();
$fn();
$r = ob_get_contents();
ob_end_clean();
return $r;
}
/**
* Функция перезагружает модель из базы (по ключу)
* @param CActiveRecord $model
*/
public static function reloadModel(CActiveRecord &$model)
{
$class = get_class($model);
$model = $class::model()->findByPk($model->primaryKey);
}
/**
* Сохранить модель, если не сохранилась - кинуть сэйвЭксепшон, и если надо - перезагрузить после сохранения
* @param CActiveRecord $model Модель которую нужно сохранить
* @param boolean $reload Перезагрузить модель после сохранения?
* @throws SaveException
*/
public static function saveModel(CActiveRecord &$model, $reload=false)
{
if (!$model->save()) throw new SaveException($model);
if ($reload) H::reloadModel($model);
}
/**
* Функция позволяющая захватывать JavaScript из потока, и вырезать из него тэги SCRIPT
* Пример использования:
*
* $code = H::obScript(function(){
?>
<script>
alert('hello!');
</script>
<?php
});
* @param type $fn
* @param type $cutScript
* @return type
*/
public static function obScript($fn,$cutScript=true)
{
$text = H::ob($fn);
if ($cutScript)
{
$text = preg_replace("#(^[\t\n ]*<script.*?>)|(</script>[\t\n ]*$)#mui","",$text);
}
return $text;
}
/**
* Полный аналог функции obScript только для CSS (вырезает тэги <style>)
* @param type $fn
* @param type $cutScript
* @return type
*/
public static function obCSS($fn,$cutScript=true)
{
$text = H::ob($fn);
if ($cutScript)
{
$text = preg_replace("#(^[\t\n ]*<style.*?>)|(</style>[\t\n ]*$)#mui","",$text);
}
return $text;
}
/**
* Получить правильную форму числа для количества элементов.
* @param integer $number - количество
* @param array $wordsForms массив с 3-мя элементами, например такой: array('0'=>'Запись','1'=>'Записи','2'=>'Записей')
* Элементы в нем - это формы слова для количеств соответствуенно 1, 2 и 5
*
* @return string возвращает правильную форму слова. Например, для входного числа 1021 вернет "Запись", для 12 вернет "Записей", для 652 вернет "Записи"
*/
public static function numberForm ( $number, $wordsForms ) {
$cases = array( 2, 0, 1, 1, 1, 2 );
$number = abs($number);
return $wordsForms[( $number % 100 > 4 && $number % 100 < 20 ) ? 2 : $cases[min( $number % 10, 5 )]];
}
public static function cryptPassword($password)
{
$salt = self::blowfishSalt();
}
/**
* Generate a random salt in the crypt(3) standard Blowfish format.
*
* @param int $cost Cost parameter from 4 to 31.
*
* @throws Exception on invalid cost parameter.
* @return string A Blowfish hash salt for use in PHP's crypt()
*/
public static function blowfishSalt ( $cost = 13 ) {
if ( !is_numeric( $cost ) || $cost < 4 || $cost > 31 )
{
throw new Exception( "cost parameter must be between 4 and 31" );
}
$rand = array();
for ( $i = 0; $i < 8; $i += 1 )
{
$rand[] = pack( 'S', mt_rand( 0, 0xffff ) );
}
$rand[] = substr( microtime(), 2, 6 );
$rand = sha1( implode( '', $rand ), TRUE );
$salt = '$2a$' . sprintf( '%02d', $cost ) . '$';
$salt .= strtr( substr( base64_encode( $rand ), 0, 22 ), array( '+' => '.' ) );
return $salt;
}
/**
* Функция аналог print_r, за исключением того что выводит не всю глубину
* массива или объекта, а только указанную.
*
* @param any $v переменная для вывода
* @param integer $maxdepth максимальная глубина,
* если < 0 - то будет неограниченной
* @param boolean $returnResult возвращать результат? Если true - результат будет возвращен в виде переменной.
* Если false - выведен с помощью echo (поу молчанию)
* @param integer $prepend_spaces количество пробелов перед строкой
* с текстом. Как правило использовать не нужно, будет работать само.
*
* @return string
*/
public static function print_r_slice ( $v, $maxdepth = -1, $returnResult = FALSE, $prepend_spaces = 0 ) {
$result = '';
if ( is_array( $v ) || is_object( $v ) )
{
if ( $maxdepth != 0 )
{
if (is_array($v))
{
$result .= "Array()";
}
else if (is_object($v))
{
$result .= get_class($v);
}
foreach ( $v as $key => $val )
{
$result .= "\n" . str_repeat( ' ', $prepend_spaces ) . ( "[" . $key . "] => " . H::print_r_slice( $val, $maxdepth - 1, TRUE, $prepend_spaces + strlen( $key ) + 6 ) );
}
}
else if(is_array($v))
{
$result .= " Array( " . count($v) . " elements ) ";
}
else if(is_object($v))
{
$result .= " instance of " . get_class($v);
}
}
else
{
$result .= $v;
}
if ( $returnResult )
{
return $result;
}
echo $result;
}
/**
* Сортирует массив чего угодно по неким числовым индексам
* Аналог стандартной функции usort, за исключением того, что второй параметр - функция получающая сравниваемое числовое значение
*
* пример использования:
*
* $x = new StdClass(); $x->value = 51;
* $y = new StdClass(); $y->value = 6;
* $a = array($x,$y);
* H::usort($a, function($obj) { return $obj->value; });
* Рассортирует масив из объектов $x и $y по возрастанию значения поля value
*
* пример 2:
* $arr = array( array('name'=>'val1', 'value'=>10) , array('name'=>'val2', 'value'=>17));
*
* H::usort($arr, function($item) { return $item['value']; }, true);
* Рассортирует массив $arr по убыванию поля 'value' в массивах - элементах
*
* @param array $arr
* @param callable $getItemCallback функция, которая получая в качестве первого параметра элемент массива будет возвращать сравниваемое число из этого элемента
* @param boolean $directionDESC сортировать по убыванию? если нет - то по возрастанию
* @return boolean возварщает то же что и обычная функция usort
*/
public static function usort(&$arr, $getItemCallback , $directionDESC=false, $stringCompare=false)
{
$sortFunc = function($e1, $e2) use($getItemCallback, $directionDESC , $stringCompare)
{
$v1 = $getItemCallback($e1);
$v2 = $getItemCallback($e2);
if (!$stringCompare)
{
$v1 = (float)$v1;
$v2=(float)$v2;
$d = $v1-$v2;
if ($d==0) return 0;
$d = abs($d)/$d;
if ($directionDESC) $d = $d * -1;
return $d;
}
else
{
if ($v1==$v2) return 0;
return ($v1>$v2 xor $directionDESC) ? 1 : -1;
}
};
return usort($arr,$sortFunc);
}
/**
* Функция, проверяющая принадлежит ли $needle указанному массиву $haystack, если принадлежит - будет вёрнуто значение $needle, иначе - значение $overwise
* @param array $haystack массив значений (стог) - где искать
* @param mixed $needle значение (иголка) - что искать
* @param mixed $overwise значение которое должно возвратиться если иголки нет в стоге сена
* @param boolean $byKeys проверяется наличие по ключу массива а не по значению
*/
public static function tryIn($haystack,$needle,$overwise=null,$byKeys=false)
{
if ($byKeys && isset($haystack[$needle])) return $needle;
if (in_array($needle,$haystack)) return $needle;
return $overwise;
}
/**
* Превращает название из "very_long_name" в формет "veryLongName"
*
* @param string $name исходное название
*
* @return string результат
*/
public static function toCamelCase ( $name ) {
$parts = explode( "_", $name );
foreach ( $parts as $num => &$part )
{
if ( $num == 0 )
{
$part = strtolower( $part );
}
else
{
$part = ucfirst( $part );
}
}
return implode( $parts );
}
/**
* Функция, получающая месадж из соответствующего файла месаджей
* @param string $message сообщение
* @param array $vars Переменная
* @param string $file имя файла
*
* @return string сообщение
*/
static public function msg ( $message, $vars = array(), $file = 'site' ) {
return Yii::t( $file, $message, $vars );
}
/**
* Получить значение из siteConst
* В качестве параметров передаются названия ключей массива в порядке вложенности элементов, например так
* H::siteConst("limits","max_tokents_per_day","recoveryByPhone")
* возвращает тоже самое что и
* Yii::app()->params['siteConst']['limits']['max_tokens_per_day']['recoveryByPhone']
* @param string $arg0 первый ключ массива
* @param string $arg1 второй ключ массива
* @param string $arg2 и так далее
* @return array|mixed значение из констант или массив значений
*/
static public function siteConst()
{
$arr = Yii::app()->params['siteConst'];
$paramLine = "siteConst";
foreach(func_get_args() as $num=>$key)
{
$paramLine .= "[" . $key . "]";
if (!is_string($key) && !is_numeric($key)) throw new REX("Параметры переданные в siteConst должны быть числами или строками! Плохой параметр #$num: " . var_export($key,true));
if (isset($arr[$key]))
{
$arr = $arr[$key];
}
else
{
throw new REX("В настройках siteConst не найден параметр " . $paramLine);
}
}
if (is_object($arr) && is_a($arr,"ComputableValue")) $arr = "" . $arr;
return $arr;
//Yii::app()->params['siteConst']['limits']['max_tokens_per_day']['recoveryByPhone'];
}
/**
* Возвращает указанное значение из массива $_GET, если оно есть и default если нет
*
* @param string $key ключ массива. Если не задан - вернется весь массив
* @param mixed $default значение по умолчанию
*
* @return mixed значение массива $_GET или default
*/
static public function get ( $key = NULL, $default = null ) {
if ( is_null( $key ) )
{
return $_GET;
}
return isset( $_GET[$key] ) ? $_GET[$key] : $default;
}
/**
* Возвращает указанное значение из массива $_POST, если оно есть и default если нет
*
* @param string $key ключ массива. Если не задан - вернется весь массив
* @param mixed $default значение по умолчанию
*
* @return mixed значение массива $_POST или default
*/
static public function post ( $key = NULL, $default = NULL ) {
if ( is_null( $key ) )
{
return isset( $_POST ) ? $_POST : $default;//было return $_POST;
}
return isset( $_POST[$key] ) ? $_POST[$key] : $default;
}
/**
* Возвращает значение POST, если оно там в виде массива, типа вот так:
* $_POST['arr']['item1']['subitem'] === H::postNested(null, 'arr','item1','subitem')
* @param mixed $default Значение по умолчанию, если ничего не будет найдено
* @param string $key1 Первый ключ
* @param string $key2 Второй ключ
* @param string $key3 И так далее, ключей может быть сколько угодно
*/
static public function postNested($default, $key1)
{
$cur = H::post();
foreach(func_get_args() as $num=>$key)
{
if ($num>0)
{
if (!isset($cur[$key]))
{
return $default;
}
else
{
$cur = $cur[$key];
}
}
}
return $cur;
}
/**
* Возвращает значение сессии, если оно там в виде массива, типа вот так:
* $_SESSION['arr']['item1']['subitem'] === H::sessionNested(null, 'arr','item1','subitem')
* @param mixed $default Значение по умолчанию, если ничего не будет найдено
* @param string $key1 Первый ключ
* @param string $key2 Второй ключ
* @param string $key3 И так далее, ключей может быть сколько угодно
*/
static public function sessionNested($default,$key1)
{
$cur = H::session($key1);
foreach(func_get_args() as $num=>$key)
{
if ($num>1)
{
if (!isset($cur[$key]))
{
return $default;
}
else
{
$cur = $cur[$key];
}
}
}
return $cur;
}
/**
* Генерирует пароль из слогов и цифр
* @param boolean $cs Case Sensivity - Включить ли генерацию пароля с регистром?
*
* @return string пароль длинной от 8-12 символов.
*/
static public function genPass ( $cs = TRUE ) {
$maxIteration = 3;
// $numSymbol = (3*$maxIteration)+3;
$cons = 'wrtpsdfghjkzxcvbnm';
$vowel = 'eyua';
$digit = '23456789';
$c = 0;
$sylls = array(
array( $cons, $vowel, $cons ),
array( $vowel, $cons ),
array( $cons, $vowel ),
// array($vowel, $vowel),
// array($cons, $cons, $vowel),
// array($vowel, $cons, $cons),
);
$cnt = count( $sylls ) - 1;
$pass = '';
for ( $i = 1; $i <= $maxIteration; $i++ )
{
foreach ( $sylls[mt_rand( 0, $cnt )] as $sym )
{
$pass .= self::_getLetter( $sym, $cs, $c );
}
$pass .= self::_getLetter( $digit );
// if( $i==$maxIteration && strlen($pass) < $numSymbol )
// {
// $num = $numSymbol - strlen($pass);
// for($j = 0; $j <= $num-1; $j++)
// {
// $pass .= $this->_getLetter($sylls[0][$j]);
// }
// }
}
return $pass;
}
/**
* Выборка случайных букв\цифр
* @param string $s Набор символов
* @param boolean $cs Регистр
* @param int $c Каунтер
*
* @return char Случайное число или букву
*/
static private function _getLetter ( $s, $cs = TRUE, &$c = 0 ) {
$s = $s[mt_rand( 0, strlen( $s ) - 1 )];
if ( $cs && ( mt_rand( 0, 999 ) % 2 > 0 ) && ( $c < 2 ) )
{
$s = strtoupper( $s );
$c++;
}
return $s;
}
/**
* Шортег для проверки залогинен ли пользователь, возможно переделка
* => оставлен для будущего поколения
*
* @return boolean Возвращает истину если пользователь не залогинен
*/
static public function isGuest () {
return yii::app()->user->isGuest;
}
static public function emailPurifier($email){
if(!$email) return null;
$fullPattern='/[a-zA-Z0-9!#$%&\'*+\\/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&\'*+\\/=?^_`{|}~-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?/';
$res = array();
preg_match($fullPattern, $email, $res);
return H::gisset($res[0]);
}
/**
* Функция для нормализации номера телефона
*
* @param $phone Номер телефона *
*
* @return string Возвращает нормализованный телефонный номер
*/
static public function phonePurifier ( $phone ) {
if (!$phone) return null;
// TODO: Эй! Кто-нибудь слышит меня? Это я, функция phoneValidator! Пожалуйста, допишите меня! Я здесь, в классе H! Мне плохо!
$rules = array( '+', '(', ')', ' ', '-', '_', '[', ']', '{', '}', '|' );
$out = str_replace( $rules, '', $phone );
if (!strlen($out)) return $out;
if ( $out[0] == '7' OR $out[0] == '8' )
{
$out = substr( $out, 1 );
}
return $out;
}
/**
* Шортег для дампа
* @param $x Переменная для дампа
* @param int $n Вложенность массивов\объектов
* @param bool $s Подсветка кода
*/
static public function dump ( $x, $n = 100, $s = TRUE ) {
CVarDumper::dump( $x, $n, $s );
}
/**
* Получить значение из кэша
* @param string $cacheID - ID значения
* @param string $value - ссылка на переменную куда будет записано значение
* @param mixed $default - если это значение не null, и при этом !$value то $value будет задано равным $default
* @return boolean возвращает true если всё получилось, и false в противном случае
*/
static public function getCache ( $cacheID, &$value, $default = null) {
if (!is_object(Yii::app()->cache))
{
H::SentryMessage("Cache doesn't configured but used! Yii::app()->cache is " . H::getTypeName(Yii::app()->cache) ,'info' );
return false;
}
$var = Yii::app()->cache->get( $cacheID );
if ( $var === FALSE )
{
return false;
}
if( $var || is_null($default))
{
$value = $var;
}
else
{
$value = $default;
}
return true;
}
/**
* Функция генерирует ключ для кэша исходя из переданного ей объекта и имени поля
* Ключ получается в формате: Object[id].field, например User[15].userEchoId или FilledScheme[1435] или TransitRequest[15].shortDescription или даже просто SomeVar
*
* Это позволит иметь унифицированные имена ключей, которые нигде не перепутаешь и не забудешь.
* Снизит количество бардака при заполнении кэша с ключами "кто во что горазд"
*
* Логика передаваемых параметров:
* 1) К какому объекту относится этот кэш? $obj !
* Если есть конкретный реальный объект для которого сохраняется кэш - лучше всего указать его
* 2) Что за значение этот кэш содержит? $field !
* Это как-бы имя "поля" объекта, так как для одного объекта в кэше могут храниться несколько разных по смыслу значения для одного объекта, логично давать им названия
* 3) Если объект не один в природе - лучше уточнить что это за объект, указав $id
* Это позволит конкретизировать объект, если он какой-то нестандартный (стандартные - это CActiveRecord, FilledScheme, CWebUser для них указывать $id не нужно)
*
* Примеры использования:
* <pre>
* $key1 = cacheKey(H::User->model, "someData"); // Даст "User[12943].someData" (12943 - это первичный ключ юзера)
* $key2 = cacheKey(H::User, "someOtherData"); // Даст "User[265].someOtherData (265 - это ID пользователя)
* $key3 = cacheKey("UserEcho","statistics"); // Даст "UserEcho.statistics"
* $key4 = cacheKey("User","shortAbout", $user_id); //Даст "User[20213].shortAbout" (20213 - это значение из $user_id)
* $key5 = cacheKey($this, "data"); //Будучи запущено например в коде модели TransitRequest даст "TransitRequest[51].data" (предположим ID модели = 51)
* $key6 = cacheKey("MyCoolVar"); // Даст "MyCoolVar" и все собственно
* </pre>
* @param Object|string $obj объект или имя объекта (если хочется указать его вручную) - из некоторых объектов попытается извлечь id, если таковой не передан в функцию,
* Например CActiveRecord, FilledScheme и CWebUser. Последний будет работать даже для гостей, причем для каждого в отдельности (вместо id будет браться sessionId)
* @param string $field имя поля, если есть
* @param integer $id Идентификатор объекта, задавать нужно только если объект какой-то необычный
*/
static public function cacheKey($obj, $field=null, $id=null)
{
$objPart = "";
$idPart = "";
$fieldPart = "";
if (is_string($obj))
{
$objPart = trim($obj);
}
else if(is_object($obj))
{
$objPart = get_class($obj);
//Если ID пустой - попробуем извлечь его исходя из типа объекта
if (is_null($id))
{
if (H::isClassOrSubclass($obj, "CActiveRecord"))
{
$id = $obj->primaryKey;
}
else if(H::isClassOrSubclass($obj, "FilledSchemeBase"))
{
$id = FilledSchemeBase::castTo($obj)->id;
}
else if(H::isClassOrSubclass($obj, "CWebUser"))
{
if (H::User()->isGuest)
{
$objPart = 'Guest';
$id = Yii::app()->session->sessionId;
}
else
{
$objPart = 'User';
$id = $obj->id;
}
}
}
}
if (!is_null($id))
{
$idPart = "[" . $id . "]";
}
if (!is_null($field) && $field)
{
$fieldPart = "." . $field;
}
return $objPart . $idPart . $fieldPart;
}
/**
* Функция возвращает типы ошибок, сложенные в переданном значении
* @param integer $errorType число, являющееся суммой ошибок (например E_STRICT & E_DEPRECATED), или null, тогда будут вёрнуты все существующие типы ошибок
* @param boolean $returnString вернуть результат в формате строки "E_STRICT & E_DEPRECATED", если = false, то ошибки будут вёрнуты в массиве типа array(E_ALL=>"E_ALL")
* @return string|array массив или строка с названиями ошибок
*/
static public function getErrorTypes($errorType=null,$returnString=false){
$error_types = array(
E_ERROR=>'E_ERROR',
E_WARNING=>'E_WARNING',
E_PARSE=>'E_PARSE',
E_NOTICE=>'E_NOTICE',
E_CORE_ERROR=>'E_CORE_ERROR',
E_CORE_WARNING=>'E_CORE_WARNING',
E_COMPILE_ERROR=>'E_COMPILE_ERROR',
E_COMPILE_WARNING=>'E_COMPILE_WARNING',
E_USER_ERROR=>'E_USER_ERROR',
E_USER_WARNING=>'E_USER_WARNING',
E_USER_NOTICE=>'E_USER_NOTICE',
E_STRICT=>'E_STRICT',
E_RECOVERABLE_ERROR=>'E_RECOVERABLE_ERROR',
E_DEPRECATED=>'E_DEPRECATED',
E_USER_DEPRECATED=>'E_USER_DEPRECATED'
);
if (is_null($errorType))
{
$res = $error_types;
}
else
{
$res = array();
foreach($error_types as $value=>$name)
{
if ($errorType & $value) $res[$value] = $name;
}
}
if ($returnString) return implode (" & ", $res);
return $res;
}
/**
*
* @param string $cacheId ID значения в кэше
* @param mixed $value само значение
* @param integer $expire Сколько секунд до протухания?
* @param ICacheDependency $dependency Зависимость. Объект класса CCacheDependency (или одно из его подклассов)
* @return boolean true if the value is successfully stored into cache, false otherwise
*/
static public function setCache ($cacheId, $value, $expire=0, $dependency=null)
{
if (!is_object(Yii::app()->cache))
{
H::SentryMessage("Cache doesn't configured but used! Yii::app()->cache is " . H::getTypeName(Yii::app()->cache) ,'info');
return false;
}
Yii::app()->cache->set($cacheId, $value, $expire, $dependency);
}
/**
* Удалить кэш
* @param type $cacheId
* @return boolean
*/
static public function dropCache($cacheId)
{
if (!is_object(Yii::app()->cache))
{
H::SentryMessage("Cache doesn't configured but used! Yii::app()->cache is " . H::getTypeName(Yii::app()->cache),'info');
return false;
}
Yii::app()->cache->delete($cacheId);
}
/**
* Удалить кэш
* @param type $cacheId
* @return boolean
*/
static public function deleteCache($cacheId)
{
return H::dropCache($cacheId);
}
static public function divRepeater ( $count ) {
return "<span style='color: #ddd;'>" . str_repeat( ' | — ', $count ) . "</span>";
}
/**
* Отправить cообщение в Sentry
* @param string $message текст сообщения
* @param string $level одно из: error warning info debug notice
*/
static public function SentryMessage($message,$level='error')
{
if(isset(Yii::app()->sentry) && Yii::app()->sentry)
{
Yii::app()->sentry->captureMessage( $message, null, $level, TRUE );
}
}
/**
* Вывести текст на вывод stderr
* @param string $message
* @param boolean $newLine переводить на новую строку после вывода переданной строки
*/
static public function echoErr($message,$newLine=true)
{
file_put_contents('php://stderr', $message . ($newLine ? "\n" : ""));
}
/**
* Рекурсивная функция "раскручивания" вложенных массивов
* Из массива вида array("a","b","c"=>array("d","e"=>array("f"=>4),"g"=>7) сделает такой вывод:<br>
* (если в качестве префикса передать "$variable")<br>
* $variable[0]='a';<br>
* $variable[1]='b';<br>
* $variable['c']['0']='d';<br>
* $variable['c']['e']['f']=4;<br>
* $variable['c']['g']=7;<br>
* То есть получается "развертка массива" с удобным внешним видом его элементов и уровней вложенности<br>
* причем список выдается в виде массива строк, так что остается только добавить к каждой строке ";" и можно сохранять в файл<br>
*
* @param mixed $arr массив (или просто 1 переменная) который нужно "развернуть"
* @param string $prefix префикс, это имя переменной которая передается изначально
* @param boolean $semicolon флаг, определяющий, будеи ли ставиться точка с запятой в конце строки - это нужно для записи в PHP файл
* @param int $split_level
*
* @return multitype:string $split_level - номер уровня вложенности за котором нужно вставлять пустые строки между элементами
*/
public static function unrollArray ( $arr, $prefix, $semicolon = FALSE, $split_level = 2 ) {
//Если нужна точка с запятой - поставим ее!
if ( $semicolon )
{
$s = ";";
}
else
{
$s = '';
}
// Если передана обычная переменная или это пустой массив - вернем значение
if ( ( !is_array( $arr ) ) || ( count( $arr ) == 0 ) )
{
return array( $prefix . " = " . var_export( $arr, TRUE ) . $s );
}
//Если передан массив (и он не пустой)
else
{
$data = array();
foreach ( $arr as $key => $element )
{
$data = array_merge( $data, self::unrollArray( $element, $prefix . "['$key']", $semicolon, $split_level - 1 ) );
}
if ( ( $split_level > 0 ) && ( end( $data ) != '' ) )
{
$data[] = "";
}
return $data;
}
}
/**
* Функция получения максимальной глубины вложенности указанного массива
* Пример:
* <code>
* $a[0][3][1]=5;
* echo get_array_max_depth($a);//Вернет "3";
* </code>
*
* @param array $arr массив
*
* @return number максимальная глубина вложенности
*/
public static function getArrayMaxDepth ( $arr ) {
if ( !is_array( $arr ) )
{
return 0;
}
$max = 0;
foreach ( $arr as $ar )
{
$depth = self::getArrayMaxDepth( $ar );
$max = $depth > $max ? $depth : $max;
}
return $max + 1;
}
/**
* Выводит содержимое переменной в виде Alert'а (через тэг <script>)
*
* @param mixed $var
*/
public static function print_alert ( $var ) {
$data = print_r( $var, TRUE );
$data = json_encode( $data );
echo "<script>alert($data);</script>";
}
/**
* Шорттэг для контроллера
*
* @return CController
*/
static public function controller () {
return Yii::app()->getController();
}
/**
* Шорттэг для рендера капчи
*
* @param string $view Путь до вьюшки
* @param array $params Передаваемые параметры
*
* @return string Возвращает весь контент вьюшки
*/
static public function renderCaptcha ( $view, $params = array() ) {
return self::render( $view, $params, '//captcha/' );
}
/**
* Шорттэг для рендера аяксовой вьюшки
*
* @param string $view Путь до вьюшки
* @param array $params Передаваемые параметры
*
* @return string Возвращает весь контент вьюшки
*/
static public function ajaxRender ( $view, $params = array() ) {
return self::render( $view, $params, '//ajax/' );
}
static public function render ( $view, $params = array(), $path = NULL ) {
return Yii::app()->getController()->renderPartial( $path . $view, $params, TRUE );
}
/**
* Оборачивает текст в блок с заданным цветом
*/
public static function colorize ( $color = "black", $text ) {
return "<span class='colorized' style='color:" . $color . ";'>" . $text . "</span>";
}
/**
* Функция маскировки значения.
* Если количество скрываемых значений выше, чем количество символов в переменной,
* то количество скрываемых символов будет уменьшаться до тех пор, пока не будет равно количеству видимых символов.
*
* @param string $var Значение где нужно скрыть данные
* @param int $countFromEnd Количество звездочек
* @param int $visibleSymbols Количество видимых символов
*
* @return string Строка со скрытыми значениями
*/
static public function mask ( $var, $countFromEnd = 3, $visibleSymbols = 2 ) {
while ( ( strlen( $var ) - $visibleSymbols ) < $countFromEnd )
{
$countFromEnd--;
}
return substr_replace( $var, str_repeat( '*', strlen( substr( $var, -$countFromEnd ) ) ), -$countFromEnd );
}
/**
* Шорттэг для маскировки email'а
*
* @param string $var
*
* @return string
*/
static public function maskEmail ( $var ) {
$v = explode( '@', $var );
$v[0] = H::mask( $v[0], 20, 2 );
$out = implode( '@', $v );
return $out;
}
/**
* проверяет принадлежит ли данный объект к классу (напрямую или опосредовано)
* @param Object $object
* @param String $class
* @return boolean
*/
public static function isClassOrSubclass($object,$class)
{
if (is_object($class)) $class = get_class($class);
if (is_object($object))
{
if (get_class($object)==$class) return true;
if (is_subclass_of($object, $class)) return true;
}
else if (is_string($object))
{
if ($object==$class) return true;
if (is_subclass_of($object,$class)) return true;
}
return false;
}
public static function spoiler($title,$content,$return=false)
{
static $spoilerNum=0;
$result = "<div class='spoiler closed' id='spoiler-div-{$spoilerNum}'>";
$result.="<span>$title</span><button class='btn btn-small btn-show'>Показать</button><button class='btn btn-small btn-hide'>Скрыть</button>";
$result.="<div class='spoiler-content'>" . $content . "</div>";
$result.= "</div>";
$result.= H::obScript(function() use($spoilerNum){?>
<script>
$(function() {
if (!window.spoilerEnabled)
{
window.spoilerEnabled=true;
$('#spoiler-div-<?=$spoilerNum?> > .btn-show').on('click',function(){
$('#spoiler-div-<?=$spoilerNum?>').removeClass('closed').addClass('opened');
return false;
});
$('#spoiler-div-<?=$spoilerNum?> > .btn-hide').on('click',function(){
$('#spoiler-div-<?=$spoilerNum?>').removeClass('opened').addClass('closed');
return false;
});
}
});
</script>
<style>
/** Спойлер **/
.spoiler
{
border:1px solid #ddd;
border-radius:3px;
padding:3px;
}
.spoiler .spoiler-content
{
border:1px inset #ddd;
border-radius:3px;
padding:3px;
margin-top:3px;
}
.spoiler.closed .spoiler-content
{
display:none;
}
.spoiler.closed button.btn-hide
{
display:none;
}
.spoiler.opened button.btn-show
{
display:none;
}
/** Спойлер закончился **/
</style>
<?php }, false);
$spoilerNum += 1;
if ($return) return $result;
echo $result;
}
/**
* Проверяет, реализует ли заданный класс некий заданный интерфейс
* @param string|object $className объект или название класса
* @param string $interfaceName название интерфейса
* @return boolean
*/
public static function isImplements($className,$interfaceName)
{
$ifaces = class_implements($className);
if (in_array($interfaceName,$ifaces)) return true;
return false;
}
/**
* Функция определяет, запущено ли данное предложение из консоли
* @return boolean
*/
static public function isConsole()
{
return !H::isClassOrSubclass(Yii::app(), "CWebApplication");
}
/**
* Быстрый доступ к сессии, позволяет считывать и записывать значения
*
* @param $key Ключ
* @param mixed $value Значение, которое нужно записать.
* @param boolean $remove Удалить значение?
*
* @return mixed Возвращает значение из сессии, если не задано $value, либо, если оно задано - записывает туда новое значение = $value
*/
static public function session( $key, $value = NULL , $remove=false ) {
static $sessionEmulator=null;
$ret=false;
//Если эмулятор не определен
if (is_null($sessionEmulator))
{
if (H::isConsole())
{
//Создаём эмулятор
$sessionEmulator = array();
}
else
{
//отключаем эмулятор сессии
$sessionEmulator = false;
}
}
//Если эмулятор сессии отключён
if ($sessionEmulator===FALSE)
{
if ( !is_null( $value ) )
{
$ret = $value;
Yii::app()->session[$key] = $value;
}
else
{
$ret = Yii::app()->session[$key];
if ($remove)
{
unset(Yii::app()->session[$key]);
}
}
}
//Если эмулятор сессии задан, то используем его
else if (is_array($sessionEmulator))
{
if (is_null($value))
{
$ret = H::gisset($sessionEmulator[$key]);
if ($remove)
{
unset($sessionEmulator[$key]);
}
}
else
{
$sessionEmulator[$key] = $value;
$ret = $value;
}
}
return $ret;
}
/**
* возвращает URL реферера, если данная URL находится на этом же сайте - отрезает от нее имя домена и прочие повторяющиеся части
*/
static public function referrerUrl () {
$refUrl = Yii::app()->request->urlReferrer;
$curUrl = Yii::app()->request->hostInfo . Yii::app()->request->baseUrl;
$minLen = min( array( strlen( $refUrl ), strlen( $curUrl ) ) );
$equalLen = 0;
for ( $i = 0; $i < $minLen; $i++ )
{
$s1 = substr( $refUrl, $i, 1 );
$s2 = substr( $curUrl, $i, 1 );
if ( $s1 == $s2 )
{
$equalLen++;
}
else
{
break;
}
}
$refUrl = substr( $refUrl, $equalLen, strlen( $refUrl ) - $equalLen );
return $refUrl;
}
/**
* Вывод тултипа
*
* @param $key alias тултипа
* @param $size Размер тултипа, по умолчанию 16, поддерживается и 24.
*
* @return mixed
*/
static public function tooltip ( $key, $size=16 ) {
if (H::isConsole())
{
Yii::import("application.controllers.PageController");
$controller = new PageController('page');
}
else
{
$controller = Yii::app()->controller;
}
return $controller->widget( 'widgets.WTooltip', array( 'key' => $key, 'size'=>$size ), TRUE );
}
/**
* Вывод тултипа с произвольным текстом
*
* @param $text текст тултипа
* @param $size Размер тултипа, по умолчанию 16, поддерживается и 24.
*
* @return mixed
*/
static public function rawTooltip ( $text, $size=16, $options = array() ) {
return Yii::app()->controller->widget( 'widgets.WTooltip', array_merge(array( 'text' => $text, 'size'=>$size ), $options), TRUE );
}
/**
* Логиним пользователя в систему
*
* @param $id ID пользователя
*
* @return mixed
*/
static public function login ( $id ) {
return Yii::app()->user->login( new CUserIdentity( $id, NULL ) );
}
/*
* Украшалка телефона. Если длина телефона != 10,
* возвращает то, что получила
* @param $phone String номер телефона
*/
static public function phoneDecoration($phone){
if(strlen($phone)!=10) return $phone;
return "+7-" . substr($phone,0,3) . "-" . substr($phone,3,3) . "-" . substr($phone,6,2)."-" . substr($phone,8,2);
}
/**
* Сокрощалка для createUrl
*
* @param $route
* @param array $params
* @param string $ampersand
*
* @return string
*/
static public function url ($route, $params = array(), $ampersand = '&') {
return Yii::app()->createUrl($route, $params, $ampersand);
}
/**
* Возвращает текущего пользователя (аналог Yii::app()->user)
* @return ModelizedWebUser
*/
static public function User()
{
if (H::isClassOrSubclass(Yii::app(), "CWebApplication"))
{
$user = Yii::app()->user;
}
else if (H::isClassOrSubclass(Yii::app(), "CConsoleApplication"))
{
$user = new ConsoleUser();
}
else
{
$user = H::DummyObj();
}
return $user;
}
/**
* Функция проходит по переданной модели, и всем моделям связанным с ней, и связанным с ними рекурсивно и
* на каждой из моделей вызывает переданную функцию
* @param CActiveRecord $model Модель с которой нужно начать обход
* @param array $linkNames Массив имён связей этой модели а также других моделей, связанной с ней
* @param callable $func Функция принимающая параметр CActiveRecord $model
* @param boolean $onlyReturnModels Только вернуть список моделей
*/
public static function walkLinkedModels($model,$linkNames,$func, $onlyReturnModels=false)
{
throw new RuntimeException("Функция walkLinkedModels не доделана!");
$relations = $model->relations();
$modelsToWalk = array($model);
foreach($relations as $relname->$rel)
{
if (in_array($relname,$linkNames))
{
if (is_array($model->$rel))
{
foreach($model->$rel as $related_model)
{
}
}
}
}
}
/*
* Отрисовывает виджет оповещений
* @param int $num - максимальное количество сообщений для показа, по умолчанию - 5
*/
public static function notices($num = 5){
Yii::app()->getController()->widget('application.views.widgets.WNotices', array('showNum' =>$num));
}
public static function listTzByContinents()
{
$contNames = array('Asia'=>'Азия','Europe'=>'Европа','America'=>'Америка','Pacific'=>'Тихий океан','Indian'=>'Идийский океан','Australia'=>'Австралия'
,'Atlantic'=>'Атлантический океан','Africa'=>'Африка');
$tz_names = DateTimeZone::listIdentifiers(DateTimeZone::ALL);
$continents=array();
foreach($tz_names as $tz)
{
$parts = explode("/",$tz);
if (count($parts)>1)
{
if (isset($contNames[$parts[0]]))
{
$continents[$contNames[$parts[0]]][] = array('name'=>$parts[1],'tz'=>$tz);
}
}
}
return $continents;
}
/**
* Нечеткое сравнение строк
* @param первая строка $str1
* @param вторая строка $str2
* @param минимальный кусочек интервала сравнения $minSize
* @param максимальный кусочек интервала сравнения $maxSize - если равен 0, то будет задан автоматически
* @param string $encoding кодировка текста (обычно - utf-8)
* @return float число от 0 до 1 - процент совпадения.
*/
public static function fuzzyCompare($str1,$str2,$minSize=2,$maxSize=4,$encoding='utf-8')
{
$s1 = mb_strlen($str1,$encoding);
$s2 = mb_strlen($str2,$encoding);
if ($maxSize==0) $maxSize = min($s1,$s2);
$maxSize = min($maxSize,$s1,$s2);
$cnt = 0;
$num = 0;
if ($s1>$s2)
{
$from = $str1;
$where = $str2;
$S = $s1;
}
else
{
$from = $str2;
$where = $str1;
$S = $s2;
}
for($size = $minSize; $size<$maxSize; $size++)
{
//echo "size:" . $size . "\n";
for ($i=0;$i<$S - $size+1; $i++)
{
$cnt+=1;
$part = mb_substr( $from,$i,$size,$encoding);
//echo $part . " ";
if ( mb_strpos($where,$part,0,$encoding)!==FALSE )
{
//echo "!";
$num+=1;
}
//echo "\n";
}
}
//echo $cnt . ",";
//echo $num;
if ($cnt==0) return 0;
return $num/$cnt;
}
/**
* Возвращает модель бесплатного тарифа
*/
public static function getDefaulTariff(){
return Tariff::model()->findByPk(H::siteConst('tariff_options','default_tariff'));
}
/**
* Выполняет закавычивание значения для использования в sql-запросе
* @param string $value
* @return string
*/
public static function quoteValue($value)
{
return Yii::app()->db->quoteValue($value);
}
/**
* Возвращает объект, в котором есть не только поля, которые есть в исходном объекте, но вообще любые поля которые могут понядобится, и все они равны default
* @param object $obj
* @param mixed $default
* @return \DummyObj
*/
public static function DummyObj($obj=null,$default=null)
{
return new DummyObj($obj,$default);
}
/**
* Функция ПСЕВДОбезопасного EVAL-а.
* Умеет отлавливать нотайсы, такие как "invalid argument to foreach" или "index '0' not found in array"
* @param string $code PHP-код который нужно выполнить
* @param array $variablesToEval переменные передаваемые в eval
* @param boolean $autoThrowException бросать исключение в случае ошибки?
* @param integer $errNum ссылка на переменную куда будет записан номер ошибки
* @param string $errText ссылка на переменнуюк уда будет записано описание ошибки
* @param integer $errLine ссылка на переменную для хранения номера строки
* @param $errContext ссылка на переменную для хранения массива контекста (т.е. всех переменных которые были активны в том месте где была ошибка)
* @return boolean|mixed возвращает либо FALSE (если была ошибка) либо то значение которое вернул eval
*/
static public function safeEval($code, $variablesToEval, $autoThrowException=false,&$errNum=0, &$errText="", &$errLine=0,&$errFile="", &$errContext=array())
{
$obj = new StdClass();
$obj->errNum = 0;
$obj->errText = "";
$obj->errContext = array();
$obj->errLine = 0;
$obj->errFile = "";
$errHandler = function($errno, $errstr, $errfile, $errline, $errcontext ) use ($obj)
{
$obj->errNum = $errno;
$obj->errText = $errstr;
$obj->errContext = $errcontext;
$obj->errLine = $errline;
$obj->errFile = $errfile;
};
set_error_handler($errHandler);
$func = function() use($variablesToEval,$code)
{
extract($variablesToEval);
$result = eval($code);
return $result;
};
$result = $func();
restore_error_handler();
$errNum = $obj->errNum;
$errText = $obj->errText;
$errContext = $obj->errContext;
$errLine = $obj->errLine;
$errFile = $obj->errFile;
//Если произошла ошибка и нужно бросить исключение - так и сделаем
if ($errNum !=0 && $autoThrowException)
{
$msg = "Error [" . $errNum . "] " . $errText;
if ($errFile == __FILE__)
{
$msg .= " in eval'd code, at line " . $errLine;
$lines = explode("\n",$code);
$num =0;
foreach($lines as $line)
{
$num++;
if (abs($num - $errLine) < 4)
{
$msg .= "\n";
if ($num==$errLine)
{
$msg .= "Error is here:<b>" . $line . "</b>";
}
else
{
$msg .= $line;
}
}
}
}
else
{
$msg .=" in file " . $errFile . ", at line " . $errLine;
}
throw new REX($msg);
}
return $errNum != 0 ? FALSE : $result;
}
public static function translitR2E($russian)
{
static $r2e = array(
"А"=>"A","Б"=>"B","В"=>"V","Г"=>"G","Д"=>"D",
"Е"=>"E","Ё"=>"YO","Ж"=>"ZH",
"З"=>"Z","И"=>"I","Й"=>"Y","К"=>"K","Л"=>"L",
"М"=>"M","Н"=>"N","О"=>"O","П"=>"P","Р"=>"R",
"С"=>"S","Т"=>"T","У"=>"U","Ф"=>"F","Х"=>"H",
"Ц"=>"C","Ч"=>"CH","Ш"=>"SHCH","Щ"=>"SCH","Ъ"=>"'",
"Ы"=>"I","Ь"=>"'","Э"=>"E","Ю"=>"YU","Я"=>"YA",
"а"=>"a","б"=>"b","в"=>"v","г"=>"g","д"=>"d",
"е"=>"e","ё"=>"yo","ж"=>"zh",
"з"=>"z","и"=>"i","й"=>"j","к"=>"k","л"=>"l",
"м"=>"m","н"=>"n","о"=>"o","п"=>"p","р"=>"r",
"с"=>"s","т"=>"t","у"=>"u","ф"=>"f","х"=>"h",
"ц"=>"c","ч"=>"ch","ш"=>"sh","щ"=>"sch","ъ"=>"'",
"ы"=>"i","ь"=>"'","э"=>"e","ю"=>"yu","я"=>"ya",
);
static $prepare = array(
'шь '=>'ш ',
'чь ' =>'ч ',
'щь ' =>'щ ',
'ъ ' => 'ъ',
);
$russian = str_replace(array_keys($prepare), array_values($prepare),$russian);
return strtr($russian , $r2e);
}
/**
* Выдает значение переменной так, чтобы не генерировать слишком много текста
* @param mixed $val любая переменная(значение)
* @param boolean return Возвращать результат?
*/
public static function debugOutputValue($val, $return=true)
{
if (is_scalar($val))
{
if (is_null($val))
{
$res = "NULL";
}
else if (!is_numeric($val))
{
$res = '"' . $val . '"';
}
else if(is_bool($val))
{
$res = $res ? "TRUE" : "FALSE";
}
else if($val==0)
{
$res= "0";
}
else
{
$res= $val;
}
}
else
{
$res = H::getTypeName($val);
}
if ($return) return $res;
echo $res;
}
/**
* Выдаёт текст информации об эксепшоне, пригодный для сохранения в файл.
* @param Exception $e
*/
public static function debugExceptionOutput($e)
{
$txt ="";
$txt .= get_class($e) . ": " . $e->getMessage() . "\n";
$trace = $e->getTrace();
$pos=0;
foreach($trace as $t)
{
$txt.= $pos . ": In " . H::gisset($t['file'],'unknown file') . ":" . H::gisset($t['line'],'unknown line') . "\n ";
if (H::gisset($t['class']))
{
$txt .= $t['class'];
$txt .= $t['type'];
}
$txt .= $t['function'] . "(";
foreach($t['args'] as $num=>$val)
{
if ($num>0) $txt.=",";
$txt .= H::debugOutputValue($val);
}
$txt .= ")\n";
//$txt .= H::print_r_slice($t,2,true);
$pos++;
}
return $txt;
}
/**
* Функция работает аналогично str_replace за исключением двух вещей:
* 1) Может заменить не все вхождения а только N первых (по умолчанию одно)
* 2) В качестве первых двух параметров принимает только строки
* @param string $needle что ищем
* @param string $newText на что заменяем
* @param string $subject где ищем
* @param integer $number сколько замен выполняем
*/
public static function str_replace_n($needle,$newText,$subject,$number=1)
{
$s = $subject;
for($i=0;$i<$number;$i++)
{
$pos = strpos($subject,$needle);
if ($pos===FALSE) return $s;
$len = strlen($needle);
$s = substr($s,0,$pos) . $newText . substr($s,$pos+$len,strlen($s) - $pos-$len);
}
return $s;
}
public static function markGuest(){
if(H::User()->isGuest){
if(!H::session('visitStartUrlMark')){
H::session('visitStartUrlMark', Yii::app()->request->requestUri);
}
}
}
/**
* Простая функция для преобразования HTML в текст
* @param type $html
*/
public static function html2text($html)
{
//1) Преобразуем все ссылки в "обычный текст"
while(preg_match("#<a.*?href\ *=\ *['\"](?P<href>.*?)['\"].*?>.*?</a>#imu",$html,$matches))
{
$html = H::str_replace_n($matches[0],$matches['href'],$html,1);
}
while (preg_match("#<br.*?>|</p>#ium", $html,$matches))
{
$pos = strpos($html,$matches[0]);
$len = strlen($matches[0]);
$cut = substr($html, min($pos-3,0),$len+6);
if (strpos("\n",$cut)!==false)
{
$newText = "";
}
else
{
$newText = "\n";
}
$html=H::str_replace_n($matches[0], $newText,$html);
}
while (preg_match("#</?[a-z]+[^>]?>#",$html,$matches))
{
$html = H::str_replace_n($matches[0],"",$html,1);
}
return $html;
}
/**
* Функция парсит URL с помощью стандартного UrlManager'а и возвращает роут и параметры
* @param string $url URL который надо распарсить
* @return array() - возвращает массив с ключами route и params
*/
public static function parseUrl($url=null)
{
if (is_null($url)) $url = Yii::app()->request->url;
$preGet = $_GET;
//Очистим GET
$_GET=array();
//Создадим новый запрос, который умеет вручную задавать requestUri
$request = new ManualHttpRequest();
//Зададим requestUri
$request->setRequestUri($url);
//Получим роут
$route = Yii::app()->urlManager->parseUrl($request);
//Получим набор GET-параметров
$params = H::get();
//Запишем тот GET который был
$_GET = $preGet;
return array('route'=>$route,'params'=>$params);
}
}
/**
* DummyObj!!!!!!
*/
class DummyObj
{
private $obj=null;
private $default=null;
public function __construct($srcObj,$default=null)
{
if (is_object($srcObj))
{
$this->obj = $srcObj;
}
else
{
$this->obj = new stdClass();
}
$this->default = $default;
}
public function __get($field)
{
if (property_exists($this->obj,$field) || isset($this->obj->{$field})) return $this->obj->$field;
return $this->default;
}
public function __isset($name)
{
return property_exists($this->obj,$name);
}
public function __call($name,$arguments)
{
return (method_exists($this->obj, $name)) ? call_user_func_array(array($this->obj,$name),$arguments) : $this->default;
}
}//Это конец DummyObj!!!!!!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment