<?php
/**
* This is a base class for console command
*/
class ConsoleCommand extends CConsoleCommand {
const LOG_FILE_MASK = 'yiic_%d-%02d-%02d_%02d-%02d_%s-%s.log';
/**
* A curl_* resource
*/
private $curlResource;
/**
* Running profilers
*/
private $profilers = array();
/**
* Selected action
*/
private $_action;
/**
* Cli args
*/
private $_args;
/**
* Инициализация
*/
public function init() {
parent::init();
mb_internal_encoding('utf-8');
ignore_user_abort(true);
set_time_limit(0);
Yii::app()->setImport($this->import());
}
/**
* Установка импорта классов
*/
public function import() {
return array();
}
/**
* Деструктор.
* Закрывает curl ресурс
*/
public function __destruct() {
if (is_resource($this->curlResource))
curl_close($this->curlResource);
}
/**
* Закончить выполнение скрипта выводом ошибки
* @param string $message Сообщение ошибки
* @param mixed Переменные для вывода через var_dump
*/
public function terminate($message) {
echo '[error] '.$message.PHP_EOL;
$args = func_get_args();
array_shift($args);
// if (!empty($args))
// call_user_func_array('var_dump', $args);
// create log dump
$file = Yii::getPathOfAlias('logs').'/'.sprintf(self::LOG_FILE_MASK, date('Y'), date('m'), date('d'), date('H'), date('i'), $this->name, $this->_action);
file_put_contents($file, 'Log created at '.date('r').PHP_EOL);
file_put_contents($file, 'Message: '.$message.PHP_EOL, FILE_APPEND);
$dump = null;
foreach ($args as $i => $arg) {
$dump .= 'Arg #'.$i.': '.var_export($arg, true).PHP_EOL;
}
file_put_contents($file, $dump.PHP_EOL, FILE_APPEND);
echo 'Log saved to file '.$file.PHP_EOL;
Yii::app()->end(1);
}
/**
* Saves action and args
*/
public function beforeAction($action, $args) {
if (parent::beforeAction($action, $args)) {
$this->_action = $action;
$this->_args = $args;
return true;
}
return false;
}
/**
* Отправить GET-запрос.
* При получении пустого результата (CURLE_GOT_NOTHING) выполнит запрос ещё раз.
* @param string $url
* @param array $config Массив для curl_setopt_array()
*/
public function getUrlContents($url, array $config = array()) {
// echo '[debug] retrieving url: '.$url.PHP_EOL;
$ch = $this->getCurlResource();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt_array($ch, $this->curlOptions());
curl_setopt_array($ch, $config);
$result = curl_exec($ch);
if ($result === false) {
$error = curl_error($ch);
$errno = curl_errno($ch);
if ($errno == CURLE_GOT_NOTHING)
return $this->getUrlContents($url);
else
throw new RuntimeException('Curl error ('.$errno.') "'.$error.'"');
}
return $result;
}
/**
* Отправить POST-запрос с полями.
* @param string $url
* @param array $data Массив полей POST-запроса
* @param array $config Массив для curl_setopt_array()
*/
public function performPostRequest($url, array $data = array(), array $config = array()) {
// echo '[debug] performing post request: '.$url.PHP_EOL;
$ch = $this->getCurlResource();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
curl_setopt_array($ch, $this->curlOptions());
curl_setopt_array($ch, $config);
$result = curl_exec($ch);
if ($result === false) {
$error = curl_error($ch);
$errno = curl_errno($ch);
throw new RuntimeException('Curl error ('.$errno.') "'.$error.'"');
}
return $result;
}
/**
* Перекодировать текст cp1251->utf-8
*/
public function convertToCp($string) {
return mb_convert_encoding($string, 'cp1251', 'utf-8');
}
/**
* Перекодировать текст utf-8->cp1251
*/
public function convertToUnicode($string) {
return mb_convert_encoding($string, 'utf-8', 'cp1251');
}
/**
* Старт профайлинга
* @return integer Номер рабочего профайлера
*/
public function beginProfile() {
return array_push($this->profilers, microtime(true));
}
/**
* Закончить профайлинг и вывести затраченное время
* @param integer $n Номер профайлера
* @param string $title Строка, поясняющая выполненную работу
*/
public function endProfile($n, $title) {
if (!isset($this->profilers[$n-1]))
$this->terminate('Invalid profiler number!', $n);
$time = microtime(true) - $this->profilers[$n-1];
echo '[profiling] '.$title.":\t".round($time, 3).PHP_EOL;
}
/**
* Запрашивает подтверждение
* @param string $message Сообщение
* @param char $default Выбираемый по умолчанию вариант (y/n)
* @return boolean Согласился ли пользователь на подтверждение
*/
public function requestConfirm($message, $default = 'y') {
$this->resetInputBuffer();
$options = array('y' => true, 'n' => false);
$default = (in_array($default, array_keys($options)) ? $default : 'y');
$print_option = function ($option) use ($default) { return $option == $default ? strtoupper($option) : $option; };
echo '[confirm] '.$message.' ['.$print_option('y').'/'.$print_option('n').']: ';
stream_set_blocking(STDIN, 1);
$line = strtolower(fgets(STDIN));
$alternate_option = ($default == 'y' ? 'n' : 'y');
if (substr($line, 0, 1) == $alternate_option)
return $options[$alternate_option];
else
return $options[$default];
}
/**
* Запрашивает выбора из нескольких вариантов.
* Запрос будет идти до тех пор, пока пользователь не выберет один из варинатов.
* @param string $message Сообщение
* @param string[] $items Список вариантов
* @param string $default Выбираемый по умолчанию
* @return string Выбранный вариант
*/
public function requestSelection($message, array $items, $default = null) {
$this->resetInputBuffer();
echo '[select] '.$message.' ['.implode(',', $items).']: ';
stream_set_blocking(STDIN, 1);
$selected = trim(fgets(STDIN));
if (in_array($selected, $items))
return $selected;
elseif ($default !== null)
return $default;
else
return $this->requestSelection($message, $items);
}
/**
* Вывести отладочную информацию
*/
public function debug($string) {
echo '[trace] '.$string.PHP_EOL;
}
/**
* Decodes html entities
*/
public function decodeHtmlEntities($string) {
return html_entity_decode($string, ENT_QUOTES, 'UTF-8');
}
/**
* Очищает буффер stdin
*/
private function resetInputBuffer() {
stream_set_blocking(STDIN, 0);
while (fgets(STDIN) !== false);
}
/**
* Список опций, которые будут добавлены к curl
*/
protected function curlOptions() {
return array();
}
/**
* Получение curl-ресурса
* @return resource
*/
private function getCurlResource() {
if ($this->curlResource === null)
$this->curlResource = curl_init();
return $this->curlResource;
}
}