Архив рубрики: PHP

PHP + PDO + SQL Server + SQL-запрос LIKE = возможные проблемы

Если у вас возникает ошибка

SQLSTATE[IMSSP]: Tried to bind parameter number 0.  SQL Server supports a maximum of 2100 parameters.

при запросе типа

SELECT * FROM table_name WHERE name LIKE 'nick'

с использованием подготовленного SQL-запроса в PHP PDO на сервер БД Microsoft SQL Server, то знайте в чем беда: функция prepare() уже сама проставит все кавычки и отметки (юникод или ASCII), за неё это не следует делать. А теперь конкретный пример: есть запрос SELECT * FROM table_name WHERE name LIKE ‘%<something>%’ Дабы использовать всю мощь PDO в борьбе с SQL-инъекциями следует использовать методы prepare и execute. Как это делать неправильно:


$sql = "SELECT * FROM table_name WHERE name LIKE N'%:name%'";

$db = new PDO("...");

$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // catch error via normal "try ... catch"

$statement = $db->prepare($sql);

$statement->execute(array(':name' => 'Наташа'));

Казалось бы, всё правильно. Мы поставили символ N в $sql, который говорит SQL Server, что поиск пойдет по тексту в кодировке юникод, обрамили сам запрос в кавычки. Но нет! Лезут ошибки. А дело оказалось в том, что prepare() сам уже проставит всё, что нужно. Таким образом правильный код выглядит следующим образом:


<strong>$sql = "SELECT * FROM table_name WHERE name LIKE :name";</strong>

$db = new PDO("...");

$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // catch error via normal "try ... catch"

$statement = $db->prepare($sql);

<strong>$statement->execute(array(':name' => '%Наташа%'));</strong>

Помог ответ на этот вопрос (хотя там ошибка другая у товарища). И еще, после дочитал-таки официальный ман по теме и оказалось в последнем примере как раз говорится о такой ошибке. В общем, вся сложность в её выявлении оказалось в неадекватном сообщение об ошибке в SQL Server.

ModX на Linux + удаленный Microsoft SQL Server ? love

Так вышло, что надо было реализовать следующую конфигурацию:

Linux (Debian) + Apache + PHP + ModX revolution + удаленный MS SQL Server

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

  1. ModX 2.1+ использует Microsoft SQL драйвер для PHP (это набор функций типа sqlsrv_*). Однако этот драйвер был выпущен только для Windows платформы. Будущий релиз на Linux крайне туманен.
  2. Есть возможность использовать открытый драйвер  FreeTDS, но тогда придётся все функции типа «mssql_*» переназначить на функции «sqlsrv_*«. Некоторые ребята сделали подобный трюк для Drupal, но при этом отмечалась общая нестабильность конфигурации и работало это только для MS SQL Server 2008.

Хорошо, что заказчик согласился сменить конфигурацию, и сейчас ModX отлично работает на Windows Azure (облачный IIS + MSSQL).

Erlang: аналогии для понимания циклов

Пришел в голову интересный способ объяснения циклов на Erlang:

Пусть А – массив:

A = [1, 2, 3, 4, 5].

Надо пройтись по каждому элементу массива и увеличить его на 1. На обычных языках программирования это делается примерно так (python):

for i in range(len(A)):
   A[i] += 1

PHP

foreach ($A as $i=>$value)
    $A[i]++;

А теперь эквивалент на Erlang:

A2 = lists:map(
   fun(Elem) ->
      Elem + 1
   end, A).

На Erlang мы использовали анонимную функцию, которая в качестве аргумента принимает одно значение и возвращает его, увеличенным на 1. Также мы ввели новый массив A2, т.к. на Erlang нельзя переопределять единожды присвоенное значение переменной. Да, по сути в Erlang переменных нет =), потому и нет классических циклов. Поэтому для реализации циклов используют или рекурсию, или проход по элементам списка с помощью функций lists:map/2, lists:foldl/3 и др.

Для каждого языка программирования свои задачи, или выводы «9 лет спустя»

Окидывая взглядом последние 9 лет практики программирования, я пришел к ряду интересных и, думаю, полезных выводов. Свою историю изучения языков программирования (далее «ЯП») проиллюстрировал ниже. Где-то отметил фреймворки на этих ЯП. Отмеченные фреймворки, как правило, давали новую мотивацию и открывали новые горизонты в изучении и использовании этих ЯП.

Языки программирования по жизни

Языки программирования по жизни

Вывод 1: для разных классов задач – разные языки программирования

В действительности, достаточно хорошо изучив какой-либо язык, кажется, что на нём надо писать не только профильные приложения. Но будьте осторожны! На этом пути вы можете впасть в состояние «вбивания гвоздей микроскопом». Так рождаются демоны (постоянно висящие процессы, типа серверов) на PHP, веб-сервера на JavaScript, веб-приложения на C++ и прочее. В качестве эксперимента – это прекрасно, но всё становится гораздо ужасней, когда что-то в силу своей популярности в другой области становится частым решением в других.

Хорошим примером иллюстрирующим первый вывод является node.js и Erlang. На node.js с радостью накинулось большое число веб-разработчиков, ведь все знают JavaScript! Попробовав домашние проекты на этой платформе, многие начали использовать node.js в реальных проектах и в итоге столкнулись с большими проблемами, решение которых затрачивало всё больше сил. Например, отказоустойчивость таких приложений. Стоит вылезть ошибке в одном из потоков выполнения, и весь сервер падает, если только вы не оградились везде, где только можно try-catch блоками. Или горизонтальное масштабирование. Тут вообще беда. И рождаются костыли-костыли-костыли.

Другое дело Erlang, который изначально «by-design» создавался для больших телекоммуникационных систем. Писать на нём серверное приложение — сплошное удовольствие. Хотите постоянно работающий сервер, которым можно управлять по telnet? Да легко! Держите встроенный пакет gen_tcp. Горизонтальное масштабирование существующего приложения? Вам скорей всего придется поменять пару строчек, где описывается передача сообщений другим функциям, — добавить в них отправку сообщений на другие ноды. Тоже и с отказоустойчивостью (привет супервизорам), обработкой бинарных данных и пр. пр.

Вывод 2 – не упускайте возможности изучать новые ЯП и/или их популярные фреймворки

Этот вывод вытекает из первого. Для каждой задачи есть свой подходящий ЯП или фреймворк, только вы о них можете пока  не знать. Поэтому необходимо как можно больше изучать новые ЯП и фреймворки.

Существует две основные когорты ЯП:

  1. Си-подобные: С++, С#, Java, PHP, JavaScript, ActionScript и др.
  2. LISP-подобные: Erlang, Python, Ruby, Perl и др.

Если вы знаете хотя бы один язык из каждого класса, то считайте, что вы знаете и все остальные ЯП.) Исключениями можно считать Assembler и языки-приколы, типа Brainfuck. Кстати, часто различить эти классы ЯП можно по наличию/отсутствию кортежей и обрамлению условных операций и циклов в фигурные скобки.

Я не стал разбивать на группы ООП, функциональные и процедурные парадигмы программирования, т.к. по большому счету почти любой подход можно использовать почти в любом языке (например, функциональный подход в Java). Другое дело, что язык изначально для этого не создавался (см. вывод 1;-) и такие извороты выглядят крайне противоестественно. Исключение Python. Он изначально разрабатывался мульти-парадигмальным.

Мой топ-рейтинг открытий типа: «А-а-а! Так вот с помощью чего это надо было делать!»:

1.  Zend Framework (на PHP)

Ну нафига я писал свою глючную библиотеку для работы с БД? О боги, а зачем я каждый раз придумывал новую архитектуру для каждого нового веб-приложения? MVC, Zend_Db, Zend_Action даруют возможность писать веб-приложения быстрее, а код делать надежным!

2.  Erlang

Боже! Ну почему я потратил кучу времени на написание этого простого демона на Java, если в Эрланге это можно было сделать парой десятков строчек, да и работало бы безотказно, да и масштабировать было бы проще!

3.  Octave

Так, надо бы быстрое преобразование Фурье… О, Matlab! Ну что, пошли на страшное преступление в ближайший торрент-трекер. Хотя ладно, вот есть бесплатная библиотечка для любимого PHP. Эхх…что-то как-то всё грустно и медленно. Octave? Octave… Octave! Мега-удобный синтаксис работы с матрицами, встроенные функции для кучи математических задач, да тут еще и графики с пол пинка строятся! Да оно еще совместимо с MatLab! А еще open-source!

4.  KnockoutJS (на JavaScript).

Как же мне надоели эти простыни с кодом, запутанная логика работы с объектами на странице, эти бесконечные onSomeEvent функции. Как бы хотелось MVC, но вот только на клиенте. Чтобы вот есть у тебя модель данных и при её изменении автоматически всё само менялось на странице. Добавил к ней объект «Задача», а на странице возьми и появись соответствующий блок для новой задачи.

KnockoutJS, как ты вовремя!

5.  Django (на Python)

Да-да, Zend Framework, ты не плох, но ты… рутинный. Каждый раз надо писать свою админку, прикручивать авторизацию, свои однотипные операции добавления, редактирования и удаления сущностей, расписывать формы ввода данных, писать однотипные виды для типичных задач, типа показа по 10 новостей на одной странице и разбивках остальных новостей по страницам. Copy-paste, copy-paste…

Ммм… что-то зачастили на хабре со своими дифирамбами во славу Django и Python.  Да давно уже поют, который год. Что ж они всё никак не угомонятся?) Ну попробуем и мы.

Так-так… значит я раскомментирую вот тут и вот тут, еще одна команда в консоли и… у меня готова полноценная админка?! Вы издеваетесь?) Так просто! А вот еще бы хотелось, чтобы в админке было удобно приписывать к разным авторам разные статьи, чтобы было красивая связь многим-ко-многим. Добавить одну строку в модель?! Ну-у, у вас совсем нет совести! Зачем же я столько времени тратил на эту рутину в зенде?»

Для этой записи хватит выводов, а то, ведь, до конца не дочитаете!) Оставим еще парочку на будущее.)

Moodle 2.2+: настраиваем регистрацию по электронной почте

Краткое содержание:

  1. Включение отправки сообщений Moodle’ом по почте пользователям
  2. Включение самостоятельной регистрации по почте
  3. Упрощение требований к паролю при регистрации
  4. Включение самостоятельной свободной записи на курс для зарегистрированных пользователей

Проблема: в Moodle не используется стандартная функция отправки почты в PHP – mail(). Вместо этого предлагается использовать для отправки системой сообщений о подтверждении самостоятельной регистрации по почте через почтовые сервера по протоколам SMTP, IMAP или ряде других.

Решение: настроить почту, используя бесплатный GMail по протоколу SMTP. Для этого:

  1. Заходим на  http://gmail.com и регистрируем почтовый ящик, например, bob@gmail.com с паролем 12345
  2. Входим в систему Moodle в качестве администратора.
  3. В левом меню выбираем «Администрирование -> Плагины -> Message outputs -> Manage message outputs«
  4. Включаем электронную почту, нажатием на глаз напротив соответствующей строки.
  5. Выбираем «Настройка» напротив Электронной почты.
  6. В графе SMTP-серверы пишем  ssl://smtp.gmail.com:465
  7. В графе Логин SMTP – адрес зарегистрированной электронной почты в GMail. В нашем примере вписываем bob@gmail.com
  8. В графе Пароль SMTP – пароль зарегистрированной почты. В нашем примере это 12345
  9. Остальные настройки не трогаем и жмем внизу на «Сохранить изменения».

Регистрация в системе по электронной почте

Небольшая инструкция, как включить регистрацию по электронной почте:

  1. В левом меню выбираем «Администрирование -> Плагины -> Аутентификация -> Настройка аутентификации«
  2. Включаем «Самостоятельная регистрация по электронной почте» (нажатием на закрытый глаз).

Упрощение требований к паролю при регистрации

И на десерт – изменяем формата вводимого пароля при регистрации. По умолчанию он слишком сложный: надо и спец-символ вставить, и чтобы большие буквы были, и маленькие, и еще цифры! Ужас!) Так что давайте облегчим жизнь пользователям и сделаем требования по-проще: от 6 символов в пароле и… всё!) Т.е. в пароле могут быть или просто цифты или просто буквы, в общем, что угодно:

  1. Администрирование -> Безопасность -> Политика безопасности сайта
  2. Находим графу Длина пароля и вводим там 6
  3. В графах Цифр, Букв в нижнем регистре, Букв в верхнем регистре и Не буквенно-цифровых символов вводим 0
  4. Жмем Сохранить изменения

Включение самостоятельной записи на курс

И раз уж такая волна, разбемся, как включить самостоятельную запись на курс:
  1. Создаем курс
  2. Включаем Режим редактирования курса (в левом меню)
  3. Управление курсом -> Пользователи -> Способы записи на курс (все в том же левом меню)
  4. В выпадающем меню Добавить способ выбираем Самостоятельная запись
  5. Настройки по умолчанию вполне нормальны, поэтому сразу жмем Добавить способ

Zend Framework: кеширование всего сайта с помощью Zend_Cache

Задача: минимизировать время загрузки сайта, используя кеширование.

Решение: использование Zend_Cache. Создаем папку ‘/application/data/cache’ с правами 776. В файле ‘/public/index.php’ после установки путей (функции set_include_path) пишем следующий код:

//// ======= caching code =============
//check if ajax, change GET request to make different cache
if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && 
	($_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest')) {
   $_GET['request_type_'] = 'ajax';
}
require_once 'Zend/Cache.php';
$frontendOptions = array('lifetime' => 600,
                              'automatic_serialization' => true,
                              'debug_header' => false,
                                   'default_options' => array(
                                   'cache_with_cookie_variables'     => true, //кешировать даже если присутствуют куки
                                   'make_id_with_cookie_variables'     => false, //в генерации id кеша не использовать куки
                              )
                         );
$backendOptions = array('cache_dir' => APPLICATION_PATH . '/data/cache');

$cache = Zend_Cache::factory('Page',
                             'File',
                             $frontendOptions,
                             $backendOptions);

$cache->start();
//// ======= end caching code =============

И… всё! Наслаждаемся увеличением скорости обработки скриптов как минимум в двое. У меня скрипт главной страницы отрабатывал в среднем за 160 мс, теперь за 70 мс.

Что произошло?

Zend_Cache состоит из набора классов фронт-энда и бек-энда.

Фронт-энд отвечает за объекты кеширования, как-то: отдельные кусочки кода, возвращаемые значения функций, объекты, целые страницы. Мы как раз используем последний – Zend_Cache_Frontend_Page – он позволяет кешировать весь сайт, работает на основе ob_start() и ob_end().

Как могли заметить самые замечательные читатели, для фронт-энда мы задаем ряд параметров. Самые интересные касаются куки и описаны в коде. Сделано это потому, что на сайте кроме как для Google Analytics куки нигде не используются, поэтому нет смысла генерировать для каждого пользователя свой кеш. Конечно, если у вас на сайте будет контент, меняющийся в зависимости от залогиненого пользователя, то о таком кешировании стоит забыть или использовать более производительный бек-энд, а лучше подумать о кешировании на местах.

Бек-энды отвечают за место хранения кеша: просто файлы в папке, sqlite, memcache и многие другие. Мы используем самый простой, но всегда доступный бек-энд – хранение кеша в файлах (Zend_Cache_Backend_File).

Ссылки

  • Официальный ман по Zend_Cache – крайне полезный и доходчивый. Даю ссылку на русском языке, но, похоже, версия на английском более детальная.

Zend Framework & Linux: шелл-скрипт для автоматического обновления

Задача: автоматизировать процесс обновления Zend Framework для всех приложений на сервере.

Решение:

  1. Создаем папку типа /var/www/libraries/ZF-last-stable/, которую и будем указывать для всех приложений в /public/index.php
  2. Создаем файл update_ZF_1.x.sh с таким содержимым:
    #!/bin/bash
    echo "Downloading new stable ZF";
    zendname="ZendFramework-1.11.1";
    wget "http://framework.zend.com/releases/$zendname/$zendname-minimal.tar.gz";
    echo "Unpacking"
    tar -xvzf "$zendname-minimal.tar.gz";
    echo "Deleting original directroy!";
    rm -r ZF-last-stable;
    mv "$zendname-minimal" "ZF-last-stable";
    exit
    
  3. Вызываем скрипт sh /var/www/libraries/update_ZF_1.x.sh

Что мы натворили: в переменной zendname мы указываем нужную версию. Архив с этой версией скачивается, распаковывается, удаляется папка zf-last-stable,  папку с разархивированным ZF переименовываем в zf-last-stable.

Получилось, правда, полуавтоматическое обновление, новую версию всё-равно придется указывать вручную. Из вариантов совсем автоматических можно использовать svn export «uri SVN репозитария с последней стабильной версией», но тогда будет неверно работать Zend_Version.

Zend Framework: идеальное веб-приложение (ч. 2 из 2)

Краткое содержание предыдущих серий: в первой части ничего неподозревающий автор вышел на, казалось бы, радужную тропинку идеального веб-приложения, однако, чем дальше он продвигался в лес, тем толще… тьфу.

В прошлой части мы:

  1. Создали структуру БД
  2. С помощью ZF Tool создали файловую структуру приложения (основной костяк, добавили модуль с рядом действий, моделей и форм, экспортировали таблицы из БД в классы приложения)
  3. Прошлись по основным паттернам

Читать далее