Блог веб-программиста

14Мар/130

Установка libssh2-php в Mac OS X

Для установки расширения ssh2 для php под маком, можно воспользоваться командой:

sudo pecl install channel://pecl.php.net/ssh2-0.12

Однако, как правило, она ругается нам следующим:

configure: error: The required libssh2 library was not found. You can obtain that package from http://sourceforge.net/projects/libssh2/
ERROR: `/private/tmp/pear/temp/ssh2/configure --with-ssh2' failed

Значит нам надо поставить libssh2 из портов MacPorts

sudo port install libssh2

Затем повторяем pecl install..., но когда нас спросят про libssh2 prefix, надо ввести /opt/local.

Всё. Перезапускаем apache и всё работает!

Связано с категорией: mac Нет комментариев
30Ноя/120

Обход ограничения max_input_vars в PHP без php.ini

Сегодня столкнулся с ограничением на количество входящих из формы в скрипт переменных в PHP.

Отвечает за это параметр max_input_vars, который по-умолчанию равен 1000.

Поскольку я разрабатываю CMS, то было бы не правильным в .htaccess менять это значение. Поэтому я решил обойти это.

С данной проблемой у меня сталкивается админка. А поскольку она не работает и не должна работать без JS, то я использовал такой JavaScript:

$("#editSaveButton").on('click', function(){
form = $("<form method=\"POST\"></form>")
.attr('action', $('#editForm').attr('action'))
.append(
$("<input type=\"hidden\" name=\"serializedData\">").val(
$("#editForm").serialize()
)
)
.append(
$("#editForm input[name=token]").clone() //@todo token name can be different
)
.appendTo($("body"))
.submit();
 
return false;
});

И вот такой код в PHP, чтобы заменить $_POST нужными данными:
 

	private function prepareSerializedData() {
		if (isset($_POST['serializedData'])) {
			$_POST = CMap::mergeArray($_POST, $this->parse_str($_POST['serializedData']));
			unset($_POST['serializedData']);
		}
	}
 
	private function parse_str($string) {
	    $parts = explode("&", $string);
	    $result = array();
	    foreach ($parts as $part) {
	    	$parsed = array();
	    	parse_str($part, $parsed);
	    	$result = array_merge_recursive($result, $parsed);
	    }
	    return $result;
	}
Связано с категорией: Code Нет комментариев
9Авг/120

Необычное проявление ошибки failed to open stream: No such file or directory

В Yii Framework, как и во многих других фреймворках, принято подгружать классы стандартной для PHP автозагрузкой.

Сегодня наткнулся на такой вот странный баг, проявившийся при разворачивании ранее рабочего сайта на другом сервере:

PHP Error [2]
include(EasmSelectEx.php): failed to open stream: No such file or directory (/Users/bethrezen/Documents/DotPlant-private/yii-framework/framework/YiiBase.php:423)
#0 /Users/bethrezen/Documents/DotPlant-private/yii-framework/framework/YiiBase.php(423): DotPlantWebApplication->handleError()
#1 /Users/bethrezen/Documents/DotPlant-private/yii-framework/framework/YiiBase.php(423): autoload()
#2 unknown(0): autoload()
#3 /Users/bethrezen/Documents/DotPlant-private/yii-framework/framework/web/CWidgetFactory.php(148): spl_autoload_call()
#4 /Users/bethrezen/Documents/DotPlant-private/yii-framework/framework/web/CBaseController.php(147): CWidgetFactory->createWidget()
#5 /Users/bethrezen/Documents/DotPlant-private/yii-framework/framework/web/CBaseController.php(173): AsmSelect->createWidget()
#6 /Users/bethrezen/Documents/DotPlant-private/protected/modules/User/widgets/AsmSelect.php(75): AsmSelect->widget()

Казалось бы проблема в отсутствующем файле, но это не так. Файл присутствует и права на месте.

Проблема же была в том, что в этом файле использовались short tags - <? вместо <?php.

В общем, странно, непредсказуемо, но логично. Ещё раз доказывает, что короткие теги не нужны.

Связано с категорией: Code Нет комментариев
27Авг/110

Бесконечная очередь и отказ от сообщений в RabbitMQ + Thumper + PHP AMPQlib

По работе столкнулся с одной задачей и решил использовать сервер очереди сообщений RabbitMQ в связке с PHP 5.3 через PHP-ampqlib и библиотеку Thumper.

Чтобы сделать Consumer(worker), который будет обрабатывать бесконечную очередь надо задать $consumer->consume(-1);. Тогда в цикле Thumper, где проверяется нужно ли нам выходить всё будет хорошо и наш обработчик будет работать вечно.

Но появился ещё один интересный вопрос - что делать, если внутри функции обработки сообщения произошел Exception? Я решил, что тогда мы отказываемся от этого сообщение и оно идет к другому обработчику. Реализовывать это лучше расширением класса Consumer:

class MyConsumer extends Consumer {
	public function processMessage($msg) {
		try {
			parent::processMessage($msg);
		} catch (Exception $e) {
			echo "Message rejected due to exception.\n".$e->getMessage()."\n";
			$msg->delivery_info['channel']->basic_reject($msg->delivery_info['delivery_tag'],true);
			//throw $e;
		}
	}
}

Соответственно ваш Consumer должен быть объектом класса MyConsumer.
Если же всё таки нужно кинуть этот Exception выше - убираем комментарий со строки throw $e;

Связано с категорией: Code Нет комментариев
4Сен/096

Декодируем gzip страницу на PHP

Недавно при разработке одного сайта, столкнулся с проблемой декодирования на PHP полученной через curl страницы, сжатой в gzip.

Допустим у нас есть код, который делает запрос через php-CURL с возвращением заголовков:

$ch = curl_init();
 curl_setopt($ch, CURLOPT_URL,$url);
 
 //curl_setopt ($ch, CURLOPT_VERBOSE, 2); // Отображать детальную информацию о соединении
 curl_setopt ($ch, CURLOPT_USERAGENT, 'Mozilla/5.0'); //Прописываем User Agent, чтобы приняли за своего
 
 curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);  // Возвращать результат
 
 curl_setopt ($ch, CURLOPT_HEADER, 1); // Наши заголовочки
 curl_setopt ($ch, CURLINFO_HEADER_OUT, 1); // Где то наткнулся на этот параметр, решил оставить
 curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT, 30);
 
 $result = curl_exec($ch);

В итоге получаем в $result нашу страницу с заголовками сервера. Проверим, закодированна ли она и дешифруем её, если нужно:

if (strstr($result,"Content-Encoding: gzip"))
 {
 $result = preg_replace("/(.*)Content\-Encoding: gzip\s+/isU","",$result);
 $result = gzinflate(substr($result, 13));
 }

Вот и всё. Если Вам нужно просто gzip контент расшифровать, то можно в substr заменить 13 на 10. (+3 из-за \n после заголовков).

Связано с категорией: Code 6 Комментарии
25Июн/090

jQuery Serialize — PHP like serialize function for jQuery

ENG: I've addapted a JavaScript serialize function by Kevin van Zonneveld to jQuery. Function works like the same named function in PHP. Be free to use it in your projects. It is especially needed when you want to post Object in AJAX (in jQuery "$.ajax()").
RUS: Я адаптировал JavaScript serialize функцию, написанную Kevin van Zonneveld, для использования с jQuery. Serialize работает также как и одноименная функция в PHP. Она хорошо выручит Вас, если Вы захотите передать в AJAX запросе Объект (JavaScript object).

Example of using: $.serialize({data: 'value'});

Связано с категорией: Code Читать полностью
29Май/090

Yii — создание своих типов Action-ов

Пишу одно прлиожение на Yii Framework. Структура приложения такова, что необходимо разграничить экшены контроллеров(CController) по папкам и сделать их типовыми.
Экшены разграничиваются легко.
Предположим, что у нас есть ряд экшенов для администрирования. Всем им надо установить какие-либо свойства или же сделать при их вызове какие-то типовые действия.
Рассмотрим на примере изменения титла страницы.
Вот код моего базового экшена:

class dotPlantAdminAction extends CAction
 {
 /**
 * Constructor.
 * Runs CAction constructor and makes some changes for Admin action type
 */
 public function  __construct($controller,$id)
 {
 parent::__construct($controller,$id);
 $this->controller->pageTitle       = dotPlant::getName() . " - Admin ";
 
}
 
public function run()
 {
 
 }
 }

В конструкторе мы сначала вызываем parent::__construct с необходимыми параметрами. Это грубо-говоря идёт инициализация базового CAction.

Допустим у нас есть контроллер SettingsController. И нам нужно сделать его на основе нашего экшена. Создаем папку  protected/controllers/Settings/. В ней создаем файл ActionAdmin.php с таким вот кодом:

class ActionAdmin extends dotPlantAdminAction
{
 public function run()
 {
    $this->controller->render('admin');    
 }
}

Видите? Нам достаточно только объявить run() и уже всё готово. При загрузке запустится необходимый нам конструктор базового контроллера с нашими действиями.

Вот по такому принципу я разграничиваю например админку в своей CMS dotPlant на Yii Framework. Слава PHP пятому!

Связано с категорией: Code Нет комментариев
10Авг/070

Yet Another Tip: Всегда проверяйте входные параметры

Данная статья находится в стадии написания. Не обращайте внимание на ашипки. Ани сделаны спицальна.

"Вот и все... и нету Билла... жадность Билла погубила!" - м/ф "Остров сокровищ", Россия

Вот сколько народу не говори: "Проверяйте входные параметры! Не доверяйте им! Юзер может их изменить! Особенно, если эти данные потом идут в базу!", а всё равно народ про это забывает. Вот совсем недавно. В одном казино заметил такую фишку..

Товарищ, писавший его наверное где-то встречал подобные статьи на сабж, но или они были написаны чайником для промо своего сайта, или просто этот человек плохо читать умеет. Кодер сий написал однажды интернет казино.. Увы ООПом тут и не пахнет... Даже массивы используются раза два-три за весь проект... Контент сайта инклудится из обычных файлов. Да, эти файлы нельзя просто так нагло прочитать, религия htaccess не позволяет. Да и выйти на папку выше тоже не получается, проверяется этот параметр регэкспом вида альфанумерик. Это умно, это молодец. Кое какие параметры у него даже проверяются на содержание коварных символов ",`,' .. Да... Это он конечно молодец и несмотря на всю убогость кода, этот момент он пытался(именно пытался) продумать...

Главная убогость кода в том, что он работает только при register_globals = on! Но это вряд ли поможет, ибо зачастую(не всегда, но бывает) переменные определяются ручками. Однако! Перейдем к игре...

В казино есть игры, которые просто работают через <form> и метод POST. Игрок делает ставку, нажимает и получает результат. Все вроде нормально. Однако! Кодер ЛОПУХ! Разве можно доверять входным данным? Никак нет! НИКОГДА! Я даже своей бабушке верю больше чем им! Так вот попробуем догадаться как выглядит исходник... Напишу на родном русском языке:
если ставка больше суммы_на_счету то пошел на фиг;
если все нормально играем;
если мы выиграли то сумма_на_счету=сумма_на_счету + ставка умноженная на коеффициент выигрыша в игре, если мы проиграли, то сумма_на_счету=сумма_на_счету - ставка;

Поскольку все люди жадные, особенно те, что заведуют казино, то естественно выиграть вам там не дадут.... От того мы проигрываем больше чем выигрываем. С этим все согласятся... Ну и отсюда естественный вывод. А что если нам проиграть, но с отрицательной ставкой? А? Словили фишку? Вот тут то весь и прикол. Если параметр не проверяется, то будет так:
сумма_на_счету = сумма_на_счету - отрицательная_ставка;
Кто хотя бы отдаленно был когда то в далеком детстве знаком с математикой помнит глупое правило: минус на минус дают плюс... Да! Оно тут срабатывает, ибо параметр не проверяется. Эта штука также подходит к условию, что ставка должна быть меньше либа равна суммы на счету, ибо отрицательное число всегда меньше неотрицательного:) Истина)

Вот такие вот косяки и приводят к огромным проблемам!

А теперь бонус, кусок злого кода на PHP:

PHP:

mysql_query("update users set cash=cash-'$stavka' where login='$l'"); /** Юзер проиграл */

if ($card==$tuz2) /** Юзер выиграл */

{

$priz=$stavka*3;

mysql_query("update game_bank set wmr=wmr-'$priz' where name='lloto'");

mysql_query("update users set cash=cash+'$priz' where login='$l'");

}

Послесловие:
Также, ещё одно вполне разумное умозаключение имеет место быть. Допустим у нас игра наперстки. Это три наперстка, надо угадать где приз. Скрипту может передаваться также ведь и параметр с номером выбранного наперстка. Если же он не проверяется, то заменив его допустим на номер 4 мы будим всегда проигрывать!
Естественно я об этой фигне сказал админу этого казино, которому было кстати 17! Он все закрыл и отблагодарил меня) Трави бобров.. ой.. твори добро.. во!

Внимание, данные действия могут попадать под статьи УК РФ!
Bethrezen

настроение: Довольное
слушаю: Lamb Of God - Purified

Связано с категорией: Code Нет комментариев