Статьи из рубрики «php» RSS

Полезные вещи на PHP

Дочерние рубрики:

Доступ к закрытым свойствам класса в PHP

Иногда встречаются ситуации, когда нужно расширить функциональность класса сторонней библиотеки; при этом нужный класс реализован так, что вместо наследования проще переписать, ибо функциональность завязана на закрытых (private) свойствах класса, для которых он не предоставляет акцессоров.

Чтобы далеко не ходить за примером, можно посмотреть на реализацию работы с базой данных в  — если требуется что-то нестандартное и не предусмотренное разработчиками — придётся извращаться. Например, если нужно добавить поддержку SELECT … FOR UPDATE/SELECTLOCK IN SHARE MODE (кстати, весьма нужный довесок для высоконагруженных сайтов с активной работой с базой данных), кажется вполне логичным унаследоваться от класса CDbCommand и добавить свои методы для организации блокировки и переопределить метод buildQuery. В теории это выглядит хорошо, но на практике имеем, что вся функциональность завязана на закрытое свойство CDbCommand::_q, в котором хранятся все параметры запроса. Кроме того, для поддержки этого хозяйства в Active Record придётся унаследоваться от CActiveRecord, а там такая же петрушка.

На правах лирического отступления: при всей моей любви к Yii, некоторые архитектурные решения выглядят весьма непродуманными и вызывают во мне любимый жест капитана Пикара: множественные косяки с закрытыми свойствами, проверки method_exists() идут вразрез с идеологией CComponent (например, использование mixin (behavior) как метода форматирования в класс, порождённый от CFormatter, закончится исключением), неудачное разбиение на методы, из-за которого наследование временами превращается в копипаст и т.д.

 — это не C++, поэтому антипаттерн Паблик Морозов (#define private public) здесь не пройдёт. К счастью, костылестроение в PHP поставлено на поток, поэтому решение всё же есть… Далее »

Автор: , опубликовано в: PHP, комментариев: нет
14
Май
2012

SQLMon для Yii

Одной из вещей, которых мне очень не хватало при разработке сайтов на  — нормального отображения всех запросов к базе данных, что дало бы возможность их последующего анализа.

Ситуацию частично исправило расширение под названием Yii DB profiler. Но остались некоторые неудобства:

  • Отображение запросов в порядке убывания времени выполнения — в принципе, это дело вкуса: при таком порядке сразу видны проблемные запросы. С другой стороны, лично мне более привычен хронологический порядок — так чётче прослеживается логика работы;
  • Prepared statements. Это просто здорово, но если повторять запрос в phpMyAdmin (например, если интересует план выполнения запроса), бывает очень муторно заменять все связанные значения. Например, для запросов вида
    [-]
    View Code MySQL
    SELECT 't'."object_id" AS "t0_c0", 't'."ymd" AS "t0_c1", 't'."black" AS "t0_c2", 't'."brown" AS "t0_c3", 't'."yellow" AS "t0_c4",
    't'."neutral" AS "t0_c5", 't'."white" AS "t0_c6", 't'."unknown" AS "t0_c7", 't'."error" AS "t0_c8", 'object'."object" AS "t1_c2",
    'object'."id" AS "t1_c0"
    FROM 'dnsbl_summary' 't'
    LEFT OUTER JOIN 'objects' 'object' ON ('t'."object_id"='object'."id")
    WHERE (((black > 0) OR (brown > 0)) AND
    (((((((((ymd=:ycp0) AND (black>:ycp1)) AND (brown=:ycp2)) AND (yellow=:ycp3)) AND
    (neutral>:ycp4)) AND (white>:ycp5)) AND (unknown=:ycp6)) AND (black>:ycp7)) AND
    (error=:ycp8))) AND (object.enabled = 1)
    LIMIT 50
    заменять все :ycpXXX на их значения немного муторно. В общем случае здесь вряд ли можно что-то сделать — заполнители параметров могут быть любыми (и даже позиционными), поэтому тупое использование str_replace может наделать делов.

Лично мне список запросов нужен обычно только для двух вещей:

  1. Оценка работы механизмов кэширования;
  2. Оценка плана выполнения запроса, составленная оптимизатором.

Первое обычно не критично (зачастую достаточно посмотреть на количество запросов), а вот второе позволяет выявить многие будущие проблемы с производительностью заранее.

В результате, взяв за основу плагин Александра, я портировал SQLMon на Yii.
Далее »

Автор: , опубликовано в: Yii, комментариев: нет
22
Ноя
2011

Преобразование ошибок в PHP в исключения

Навеяно этим сообщением на форуме.

Дано:

  • фреймворк перехватывает все возникающие ошибки (которые разрешены текущим значением error_reporting()) и аварийно завершает работу скрипта (в целях отладки/безопасности/нужное подчеркнуть);
  • имеется код, вызывающий -функцию, которая может сгенерировать предупреждение (в оригинальном сообщении это mkdir() — кидает E_WARNING, если не удаётся создать каталог)
  • местные стандарты кодирования запрещают использование оператора @ (довольно распространённая практика).

Требуется обработать возникшую ошибку без авоста скрипта. Далее »

Автор: , опубликовано в: PHP, комментариев: 8
17
Авг
2011

Перехват фатальных ошибок в Yii

Как и , помогает разработчику, отлавливая неперехваченные исключения и ошибки в коде. Как и в , реализуется это одинаково — через функции set_exception_handler() и set_error_handler(). Но, в отличие от Kohana, Yii не умеет перехватывать фатальные ошибки (E_ERROR в терминах PHP).

Как следствие, если приложение сгенерирует фатальную ошибку (например, вызов несуществующей функции), у разработчика все шансы об этом не узнать (например, на production-сервере с display_errors установленным Off). Конечно, если приложение хорошо протестировано шансы возникновения такой ситуации близки к нулю, но если приложение позволяет пользователю устанавливать какие-либо свои дополнения, то лучше узнавать о проблемах прежде, чем начальник получит кучу гневных писем :-) Далее »

Автор: , опубликовано в: Yii, комментариев: 1
7
Авг
2011

Вложенные транзакции в PDO

В есть такая особенность: отсутствие поддержки вложенных транзакций.

Вложенные транзакции бывают весьма полезны: например, у нас есть два сервиса, которые могут взаимодействовать между собой. Сервис А начинает транзакцию, что-то делает, затем вызывает сервис Б, затем подтверждает транзакцию.

Может так случиться, что сервисы А и Б разрабатываются разными людьми и разработчик сервиса Б может не знать, что сервис А уже начал выполнение транзакции. Как следствие, при использовании PDO как только сервис Б попытается начать транзакцию, PDO выбросит исключение, предупреждающее о наличии активной транзакции.

Тем не менее, такие СУБД как , и SQLite поддерживают вложенные транзакции (о чём PDO не знает). Поэтому было бы неплохо добавить поддержку вложенных транзакций для данных СУБД в PDO. Далее »

Автор: , опубликовано в: PHP, комментариев: 4
6
Авг
2011

Автоматическая проверка репутации IP-адреса

Репутация -адреса — одна из очень важных составляющих, используемых для борьбы с почтовым спамом.

Письма приходят с IP-адресов, а репутация этих адресов может сказать, является ли данный адрес ответственным за рассылку спама или нет. По некоторым данным проверка репутации IP-адресов позволяет остановить порядка 80% спама.

Как следствие, компании, занимающиеся массовой рассылкой электронных писем, должны заботиться о поддержании хорошей репутации адресов своих почтовых серверов. Далее »

Автор: , опубликовано в: PHP, комментариев: 6
3
Фев
2011

Особенности работы функции checkdnsrr()

Функция checkdnsrr() используется для проверки существования записей . Например, фреймворк использует эту функцию для проверки наличия MX-записи домена, указанного в адресе электронной почты.

Тем не менее, существуют некоторые подводные камни, связанные с использованием данной функции, о которых разработчикам нужно знать. Далее »

Автор: , опубликовано в: PHP, комментариев: нет
24
Сен
2010

DoS для PHP через imap_fetchbody

Как оказалось, если передать функции imap_fetchbody() параметр $secton, длина которого больше 1004 байт, падает по segmentation fault. На некоторых конфигурациях с применением некоторых усилий (подробности, понятное дело, разглашаться не будут) получалось вместе с положить и Apache. Далее »

Автор: , опубликовано в: PHP, комментариев: 2
16
Авг
2010

Исправление ошибки в INSERT INTO … SELECT в Kohana 3 при использовании конфигурации базы данных, отличной от default

Ситуация: нужно выполнить запрос вида

[-]
View Code SQL
INSERT INTO `table` (`col1`, `col2`) SELECT * FROM `table` WHERE `col1` <> 0;

Если использовать конфигурацию default, то всё отлично работает. Если же использовать другую конфигурацию, то можем получить ошибку соединения с базой данных и исключение. Далее »

Автор: , опубликовано в: Kohana, комментариев: нет
12
Авг
2010

Поддержка JOIN в запросах DELETE для Kohana 3

Иногда бывает полезно выполнить удаление записей в нескольких связанных таблицах, благо синтаксис позволяет. Разумеется, есть такая вещь как каскадное удаление записей, но в случае с (а именно — таблицами MyISAM) на неё надеяться не приходится.

Модуль Database из не умеет использовать JOIN с операцией DELETE. Нужно ему помочь. Далее »

Автор: , опубликовано в: Kohana, комментариев: нет
11
Авг
2010