Подписка на блог

В Телеграме помимо ссылок на заметки делюсь околодизайнерскими наблюдениями.

В Твиттере помимо ссылок на заметки пишу всякую чушь.

В Тумблере и Же-же есть автоматические трансляции. Если не работает, напишите мне: ilyabirman@ilyabirman.ru.

По РСС и Джейсон-фиду трансляции для автоматических читалок

ПХП

Позднее Ctrl + ↑

Боремся с 77 февраля

Если зайти по вот такому адресу — http://ilyabirman.ru/meanwhile/2008/02/77/ — то вместо ожидаемой страницы 404 мы увидим страницу, говорящую о том, что 77 февраля заметок нет. Это, конечно, не беда, но если это можно решить по-простому, то хочется взять, да и решить, правда?

Я это уже исправил в v1793, но на сайте пока крутится v1792 (последняя доступная всем остальным версия — v1746). Сначала я в функции, отвечающей за выдачу страницы архива, написал:

if (!e2_date_possible ($year, $month, $day)) return e2_error404_mode ();

А потом написал функцию e2_date_possible (), которая получилась не намного длиннее.

Задача: придумайте функцию e2_date_possible () лучше моей (не видя мою).

Update
Дмитрий Смирнов: Ты изобрел функцию checkdate, поздравляю!
Принимаю поздравления. Это, кстати, подтверждает правоту Болка. Тем не менее, задачка остаётся, просто к ней добавляется (в реальной жизни ненужное) условие неиспользования функциии checkdate ().

Как поднять Апач и ПХП на Айфоне

Чтобы организовать Апач и ПХП на Айфоне нам понадобится:
  • вайфай (либо куча терпения и денег, если качать всё через GPRS);
  • телефон, на котором стоят терминал, Community Sources и BSD Subsystem (не уверен, что она нужна, но у меня стояла);
  • компьютер с установленным каким-нибудь софтом для хождения по файловой системе Айфона (у меня это iBrickr).
Понятно, что поставить что-либо на Айфон благодаря Installer.app совсем не трудно, но в случае с Апачем и ПХП вопрос в том, как это в итоге заставить работать. Денвера для Айфона, как мы понимаем, нет. В общем, после того, как Апач (категория Network) и ПХП (категория Development) установлены обычным путём, нам нужно пойти в терминал и написать (осторожно, в терминале не работает бекспейс):

PATH=$PATH:/opt/iphone/bin/
export PATH


Теперь идём в httpd.conf (/etc/httpd/httpd.conf) и пишем про ПХП вот такие строчки (каждую в своё логичное место):

ScriptAlias /php /opt/iphone/bin
AddType application/x-httpd-php .php
Action application/x-httpd-php "/php/php-cgi"


Теперь идём в терминал и перезапускаем Апач:

apachectl restart

Осталось закачать скрипт с вызовом phpinfo () в /Library/WebServer/Documents/ и направить Сафари на localhost/название-скрипта.

То есть всё довольно-таки несложно. Другой вопрос — что со всем этим можно сделать интересного. Этот вопрос я пока изучаю, и у меня есть ощущение, что тут есть целый мир для экспериментов.
 5 комментариев    32   2008   Айфон   ПХП

Оптимайз — 3

Пришла в голову очередная оптимизация; не понимаю пока, будет работать или нет.

e2 сейчас уже довольно прилично тормозит — иногда генерит страницу по 0,15-0,2 сек. Причина тормозов пришла откуда не ждали: очень много времени уходит на то, чтобы просто пропарсить core.php, который уже почти 200 килобайт весит. Разбивать всё это на много файлов — будет ещё больше тормозов, т. к., как мы уже проходили, сильно тормозит include. Собственно, поэтому я и стал всё собирать в единый файл.

Значит, нужно как-то сделать так, чтобы для генерации каждой страницы парсилось только то, что нужно. Но как это сделать?

Идея такая. Ведь просто тупое считывание 200 КБ не может быть долгим, так? Тормозит, потому, что это парсится всё. А что, если мы эти 200 КБ разобъем на функциональные куски (ФК), каждый из них сделаем просто строкой, но оставим в одном файле, а при вызове функции из нужного ФК, будем вместо include’а эту строку eval ()’ить? Если это сработает, то можно пойти дальше: запихать разные ФК прямо в реестр, который мы всё равно считываем. Тогда ещё на один include меньше будет.

Или ерунда? Аргументы приветствуются.

Update: Bolk говорит, eval () работает медленнее, чем include. Ну, а что ещё можно с этим сделать?

Windows-приложения на PHP

Мне всегда хотелось писать Windows-приложения на PHP, ведь это такой замечательный язык.

Когда-то я пробовал PHPGTK, но мне сразу не понравилось. Он генерил совершенно отвратительный интерфейс, не имеющий никакого отношения к Windows. Как я понимаю, там люди просто портировали под Windows какой-то первобытный оконный интерфейс из какого-то линукса. Казалось бы, взялись за дело — ну доведите его до ума: замените вызовы своего портированного кода вызовами нормального WinAPI. Ан-нет, это не наш путь.

Но всё меняется, когда приходят они. Если за дело берутся Windows-разработчики, то на выходе получается намного более удобоваримый продукт, WinBinder. WinBinder позволяет делать нормально-интерфейсовые приложения под Windows. Больше того, он позволяет даже собрать такое приложение в exe-файл! Нужно только разобраться, как это делать (смайлик).

В общем, очень интересная штука.

Избавиться от PHPSESSID

Почему-то очень часто бывает, что если сайт открываешь в браузере первый раз в сессии, то все ссылки обрастают PHPSESSID’ами. F5 — и всё в порядке, PHPSESSID переползает из урла в куки. Мне нужно как-то сделать, чтобы PHPSESSID в урле не использовался, даже если возникли какие-то проблемы с куки.

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

Как этого добиться?

Режимы и службы

Я, наконец, решил написать про свою идеологию «режимов и служб» (РиС) — почти универсальный принцип построения стройных yet гибких PHP-приложений. Наверное, этот подход подойдёт и в случае использования других серверных языков, но про них я ничего не знаю. Принцип «режимов и служб» реализован в Plif One и в e2.

Всё началось с того, что мне никогда не нравилось, когда в веб-приложении есть несколько исполняемых php-скриптов (здесь я буду называть исполняемыми скрипты, которые содержат что-нибудь, кроме описаний функций). Типа, для главной страницы — index.php, для страницы about — about.php и так далее. Это очень неудобный (=плохой) способ, т. к. он предполагает, например, copy/paste кода дизайна во все скрипты. Многие будут возражать, что код дизайна можно вынести в отдельные файлы и инклюдить их. Да, конечно, но сам include — это уже код, одинаковый во всех файлах. При таком раскладе нельзя даже переименовать включаемый файл, потому, что это потребует правки огромной кучи других. Потом, во всех файлах могут потребоваться какие-то «общедвижковые» API, находящиеся во всяких других инклюд-файлах. Эти инклюды тоже будут повторяться из файла в файл и их нельзя будет спокойно трогать. В общем, этот подход образует довольно каменный код.

По абсолютно таинственным причинам, однако, именно он используется в подавляющем большинстве скриптов, которые я видел. Единственное исключение, которое приходит на ум — WackoWiki. Но сейчас речь не об этом. Речь о том, как сделать так, чтобы исполняемым был только один скрипт (index.php) и при это всё отлично работало. Условно все действия, выполняемые скриптом, можно поделить на 1) генерацию какого-то контента и скармливание его браузеру, и 2) обработку каких-нибудь POST-запосов.

Первый постулат принципа РиС: не бывает скриптов, которые бы хотя бы в какой-то мере сочетали первое и второе.

Режим

Термин «режим» возник очень просто: я часто делал, чтобы страницы были видны по адресам вида index.php?mode=about (mod_rewrit’ом это легко доводится до красоты, сейчас не об этом), т. е. называл переменную словом mode. Поэтому, проход по скрипту, в результате которого генерируется и скармливается браузеру какой-то контент, называется режимом. Для работы с режимами пишется функция («менеджер режимов»):

01 function modes () {
02   global $mode, $content;
03   $mode = @$_GET['mode'];
04   if (!$mode) $mode = 'frontpage';
05   @require_once 'system/'.$mode.'.php'; # например
06   if (!function_exists ($mode.'_mode')) $mode = 'error404';
07   $content = call_user_func ($mode.'_mode');
08 }


Что она делает — понятно. Ага? Каждый режим генерирует своя функция. Его внешний вид (HTML) она возвращает менеджеру режимов, а он это запихивает в глобальную переменную $content.

Служба

Проход по скрипту, в результате которого обрабатывается какая-нибудь информация из форм, например, а HTML’а браузеру не передаётся, называется службой. Службы обрабатываются так (это «менеджер служб»):

01 function services () {
02   global $service;
03   $service = @$_GET['service'];
04   if (!$service) return;
05   @require_once 'system/'.$service.'.php';
06   if (!function_exists ($service.'_service')) die ('Служба не найдена');
07   $go_to = call_user_func ($service.'_service');
08   if (!$go_to) $go_to = @$_POST['came_from'];
09   if (!$go_to) $go_to = 'http://'.$_SERVER['HTTP_HOST'];
10   header ('Location: '.$go_to);
11 }


Имея эти функции, index.php мы можем оформить примерно так:

01 <?
02 require_once 'ms.php'; # modes and services
03 services ();
04 modes ();
05 echo design ();
06 ?>


Рассмотрим теперь всё это подробнее. Сначала мы вызываем менеджер служб, потому, что это логично (смайлик). Он смотрит, не нужно ли сейчас выполнить какую службу (строки 03-04). Если не нужно, то он возвращает управление функции main (). Если же нужно, то он выполняет службу (строка 07).

Функция, реализующая службу, может вернуть URL, по которому она хочет перекинуть браузер после своего завершения (например. если функция обработала форму отправки комментария, то там может быть урл страницы со всеми комментариями). Если функция не вернула такой урл (строка 08), то тогда мы смотрим, не было ли в форме поля came_from, и если было, то считаем его значения искомым урлом. Если же и этого поля не оказалось (чего вообще-то не должно произойти, см. ниже), то мы перекидываем пользователя на главную (fallback).

Допустим, мы добрались до modes (). Это происходит, когда в параметрах index.php не прописан вызов службы (например, index.php?service=post-comment). Тогда если режим не указан, мы считаем, что мы на главной. Если функция-режим не найдена, то мы выполняем режим 404-й ошибки. Функция-режим всегда возвращает строку — HTML, который нужно показать пользователю. Разумеется, она выдаёт только ту часть HTML, которая в разных режимах разная. В результате, всё это попадает в глобальную переменную $content, вокруг которой в функции design () мы рисуем что нашей душе угодно. Точка.

Теперь про came_from. Ясно, что форма — это режим. Значит, её генерируют какие-то функции-режимы. Мы можем ввести понятие режим-форма и определить для него требование: любая форма должна содержать скрытый input с именем came_from и значением, равным $_SERVER[’HTTP_REFERER’]. Процесс добавления этого input’а можно легко автоматизировать. Тогда менеджер служб всегда будет знать, куда перекинуть браузер после выполнения службы.

Что это всё даёт? А то, что добавление новых типов страниц, функций и чего угодно на сайт, сделанный по такой схеме, становится очень простым делом — нужно просто создать файл в /system и написать в нём, что он должен делать. Всю организационно-дизайнерскую работу возмёт на себя уже готовый каркас.

Дальше, чтобы всё было совсем хорошо, можно сделать .htaccess примерно такого вида:

RewriteEngine On
RewriteRule ^services\/([^/.]+)(\/?)$ index.php?service=$1
RewriteRule ^([^/.]+)(\/?)$ index.php?mode=$1


Кроме того, что это сделает все урлы красивыми, ещё и action у формы будет иметь модный вид «services/post-comment».

Внимание! У этого подхода есть и некоторые недостатки. Если вы нашли один из них, не нужно думать, что вы большой герой, и громко про это кричать. Недостатки — это нормальное явление для всего. Вы можете просто спокойно их изложить, тогда этого не придётся делать мне. Спасибо.

Update: ужас, сколько идиотов в комментариях; не читайте их.

name ()

Нужна функция function name (string param), которая возвращает имя фактической переменной, переданной ей. Или я совсем тупой, или без debug_backtrace () тут не обойтись...

echo name ($some_var);

Должно вывести «some_var».
 3 комментария    7   2004   ПХП

SQLite рулит

Тут пишут про SQLite — базе данных, встроенной в PHP 5. Похоже, SQLite — это круто. Больше всего возбуждает:
  • отсутствие типов
  • транзакции
  • возможность засунуть в базу функцию и потом использовать её в SELECT’е или чём угодно
  • то, что вся база хранится просто в файле, т. е. 1) от хостера не требуется ничего, чтобы предоставить пользователю базу; 2) от пользователя не требуется ничего, чтобы включить поддержку баз данных в PHP 5.
Похоже, переход с mySQL на SQLite будет чем-то вроде перехода с C на PHP.

Но самое интересное, что есть вероятность, что Masterhost реализует-таки в «Панели управления» выбор между PHP 4 и PHP 5!
 4 комментария    15   2004   ПХП

Даёшь настройки в XML!

Вот человек знает как правильно писать на PHP и, в частности, как правильно писать блог. Похоже, сам-то он начитался книжек «Выучи XML за 5 минут», если считает, что XML лучше сериализованных массивов и его нужно пихать всюду... Обратите внимание на ЧПУ.

om_number ()

Мы с Дмитрием Кирсановым круче скилл ру, потому, что у нас-то есть вот какая функция:

function om_number ($number, $titles, $show_number=true) {
  $cases = array (2, 0, 1, 1, 1, 2, 2, 2, 2, 2);

  if ($number%100 > 10 && $number%100 < 20) $case = 2;
  else $case = $cases[$number%10];

  $title = $titles[$case];
  if ($show_number) $title = "$number $title";

  return $title;
}


(Копирайт его, а я взял в e2 попользоваться)

Update: Вообще, если бы функцию писал я, то она бы называлась e2_ru_noun_for_number ().
Ранее Ctrl + ↓