Created
October 31, 2014 15:20
-
-
Save MihanEntalpo/cd4d13ecd049003143e7 to your computer and use it in GitHub Desktop.
H.php из путевого
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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