четверг, 24 января 2019 г.

Интервью Расмуса Лердорфа для SitePoint

Интервью Расмуса Лердорфа для SitePoint

Автор: Kevin Yank (SitePoint.com)
Перевод: Дмитрий Лебедев (detail.phpclub.net)
Кевин Янк (Kevin Yank): Недавно участники форумов сообщества SitePoint собрались вместе и сформулировали подборку вопросов к создателю PHP, Расмусу Лердорфу. Я был доволен, когда прочитал его ответы и узнал, что человек, который изначально запустил в движение механизм PHP, видит безоблачным то, что происходит с движением open source. Перевод Дмитрия Лебедева (detail)
Он спешит преуменьшить свой вклад в то, чем является PHP сегодня, и приписывает основную долю успеха PHP большому сообществу разработчиков, за годы оставивших свой след в проекте. То есть Расмус сегодня — просто самый большой фанат PHP.
Но хватит с меня, давайте послушаем, что говорил Расмус.
В начале...
SP: Каким был ваш первый контакт с движением Open Source и что в нём такого, на что вы "подсели"?
RL: Тогда в начале и середине 90-х термин "Open Source" не существовал.
Существовало "бесплатное программное обеспечение", конечно же, и я игрался с Линуксом с самого первого релиза в 1991 году. До этого я использовал QNX и Xenix и начал играться с Minix пока меня не выручил Линукс.
Не думаю, что когда либо я пристращался к "движению". Когда у вас нет денег, чтобы купить Юникс, и вы можете скачать что-то, что работает, и даже найти людей, которые могут вам помочь поставить это и запустить, как можно обойти это? Культ никогда не играл роли.
SL: Что заставило вас разработать PHP? И что по вашему мнению этот язык может предложить, чего нет в других?
RL: Первая версия PHP была простым набором инструментов, которые я выложил вместе на мой сайт для пары проектов. Один инструмент делал высшего качества логи в базу данных mSQL, другой работал как обработчик форм. Я закончил на 30 разных маленьких CGI-программ написанных на C, когда устал от этого и соединил их в одну библиотеку на C. Затем я написал очень простой парсер, который бы брал теги из HTML-файлов и заменял их на вывод соответствующих функций в библиотеке.
Простой парсер медленно вырос до включения условных тегов, затем циклов, функций и так далее. Я никогда не думал, что пишу язык сценариев. Я просто добавлял немного функциональности в парсер, заменяющий макросы. Я по-прежнему писал всю свою логику для реального бизнеса на C.
Наконец, что на мой взгляд выделило PHP в те ранние дни и до сих пор — это то, что он [PHP] всегда пытается найти кратчайший путь в решении проблемы веба. Он не пытается стать языком сценариев общего назначения, и любой, кто ищет решения проблем интернета, найдёт прямое решение при помощи PHP. Многие альтернативы, которые претендуют на решение проблем интернета, просто слишком сложны. Когда вам нужно что-то установленное и работающее к пятнице, чтобы не надо было тратить все выходные листая восьмисотстраничные мануалы, PHP начинает выглядеть довольно хорошо.
SP: Если посмотреть на цифры, сейчас более 9 миллионов доменов используют PHP. Вы когда-нибудь думали, что PHP станет таким большим? Каково чувствовать, что ваш продукт — возможно, самая лучшая альтернатива решениям Майкрософта для веба?
RL: Во-первых, пусть будет ясно, что я не разрабатывал PHP, который мы знаем сегодня. Десятки, если не сотни людей разрабатывали PHP. Я был просто первым разработчиком.
PHP — в значительной степени совместный проект. Подумайте так: у вас есть проблема связанная с вебом. Вы можете либо пойти в магазин и купить дорогой продукт в целлофане, который может или не может решить большинство ваших проблем. Либо вы собираетесь вместе с некоторыми из тысяч людей, у которых есть точно такая же проблема, как и у вас, и вырабатываете решение, которое работает на всех из вас.
Вы не только получите решение, направленное именно на вашу проблему, вы также станете частью одинаково мыслящего сообщества, где идеи и опыт распространяются свободно. Это превосходит любой коммерческий продукт, который можно купить в магазине, и по мне это лучший способ разработки такого рода софта.
Поэтому когда люди спрашивают меня, каково чувствовать себя разработавшим что-то, что используют миллионы людей, это не соответствует моему взгляду на вещи. Наконец, я просто первый член сообщества, которое возникло вокруг одного подхода к решению проблем веба.
SP: Кого бы вы назвали своим героем? Какие люди из или извне IT воодушевляли вас?
RL: На самом деле, люди меня не воодушевляют в метафизическом смысле. Но я определённо ценю и уважаю превосходные решения сложных проблем.
SP: Как вы думаете, какое самое важное решение за годы разработок PHP вы приняли? Есть ли решения, которые в приняли и которые сейчас хотелось бы сделать по-другому?
RL: Сложно просить меня предугадать решения, которые были сделаны 6 или 7 лет назад, когда PHP использовался в общей сумме одним человеком. Не забывайте, что я не брался написать язык сценариев, который бы использовался на 9 миллионах доменов, я брался за решение проблем. Решение проблемы до 5 вечера, чтобы потом вы могли пойти в кино с подругой ведёт к тем перспективам, которые не идеальны 7 лет спустя, когда тысячам людей приходится работать над добавленной вами ночной писаниной.
Самое правильное решение, которое я принял за всё время было, возможно, отменить контроль. Открыть проект и дать любому, кто попросит, полный доступ к исходникам PHP. Это привело множество очень талантливых людей. Проект PHP, возможно, самый большой, если считать по количеству людей, которым вверяют доступ к CVS-репозитарию, где живёт код и документация.
Движение Open Source
SP: Движение Open Source всё ещё представляется многими, как "анархистское" и своего рода "опасностью для общества". Чувствуете ли вы, что оно когда-нибудь добьётся принятия мейнстримом? Если да, то как сообщество Open Source будет с этим поступать?
RL: Я полагаю, у этого вопроса есть две части.
Как и мейнстрим, продукт этого "движения" — определённо является мейнстримом. "Движение" построило интернет таким, каким мы его сегодня знаем. Оно построило стек TCP/IP, используемые в большинстве операционных систем (да, даже в Windows). Оно не только создало самый популярный веб-сервер в мире (имеется в виду Apache — прим. переводчика), но и системы DNS и MTA, которыми интернет и живёт. И если вы оглянетесь немного назад, вы поймете, что OpenSource сегодня это целая отрасль разработки программ. Все первые операционные системы были с открытым исходным кодом, потому что это был единственный разумный способ работать. Вы не могли продать кому-нибудь большой мейнфрейм без предоставления исходников мозга этой вещи. Только позднее была представлена концепция непредоставления исходного кода.
Но я полагаю, ваш реальный вопрос — что я думаю о попытках Майкрософта убедить мир, что большие группы людей, сотрудничающих, чтобы решать проблемы, как-то угрожают самой структуре общества, в котором мы живём. И я не думаю, что есть "много" людей, заявляющих это, поскольку это полная чепуха — я бы хотел считать мир хорошим местом, не наполненным людьми, которые распространяют такую нелепую идею. Давайте положим конец всем встречам больших групп людей, если на то пошло. Они могут быть злыми анархистами, которые разрушат мир.
В конце концов, принятие мейнстримом — не цель. Цель для большинства людей, которые работают над бесплатным софтом и opensource-проектами — сама технология. Это построение инструмента, который решает проблему. Это не идеология для большинства из нас, и поэтому принятие мейнстримом включает в себя лишь общепринятое использование технологии. На многих направлениях это было достигнуто, на многих это ещё впереди.
SP: PHP уделяется очень мало внимания со стороны мейнстрима IT-прессы. Чувствуете ли вы, что PHP нарочно игнорируется вне кругов Open Source?
RL: PHP — не очень захватывающая вещь. Это тонкий слой клея между веб-сервером и разными вещами, с которыми вам хочется, чтобы ваш сервер говорил.
По старой традиции Юникса мы полагаемся на маленькие специализированные добавочные библиотеки для подъёма всех тяжёлых действий с как можно меньшим вмешательством со стороны PHP. И ASP, и JSP, и Cold Fusion имеют большие компании с большими рекламными бюджетами за спиной и сами продукты становятся больше и сложнее с каждым релизом, чтобы покупатели чувствовали, что они стоят таких денег. Кто выложит 10 000 долларов за дискету и двухстраничный мануал?
Дискета и 2-страничное руководство могут на самом деле быть тем, что им нужно для решения их проблемы, и вполне будет стоить потратить 10 000 долларов на маленькое целевое решение как это. Маленькие целевые решения вызывают мало интереса у больших софтверных компаний. Концепция не масштабируется. Маленькие целевые решения без рекламного бюджета не интересуют рекламные газеты.
Так что нет, я не думаю, что это нарочно PHP получает мало внимания прессы. PHP так же восхитителен, как и зубная щётка. Вы используете её каждый день, она делает работу, это простой инструмент, и что? Кто захочет читать о зубных щётках?
SP: Уход от публичной лицензии* GNU** при переходе PHP от третьей к четвёртой версии вызвал суматоху среди сообщества Open Source. Чувствуете ли вы, что новая модель лицензирования сейчас принята и понята как наилучшее направление, которое PHP мог выбрать?
Общая Публичная Лицензия (General Public License, аббрев. GPL) — типовая лицензия на распространение программного обеспечения, представленная движением GNU. Широко используется для лицензирования свободно распространяемого ПО. Текст лицензии (прим. переводчика)
** GNU — проект развития свободно распространяемой Unix-подобной операционной системы. Сайт проекта. (прим. переводчика)
RL: PHP 3 на самом деле имел две лицензии. Поэтому мы на самом деле не перешли с GPL к чему-то ещё, а просто убрали часть GPL.
Я не вижу смысла в двойном лицензировании, и оно вызывает много путаницы. Постановкой PHP под лицензию, подобную той, под которой распространяется Apache, было разрешено многое из этой путаницы.
Двойное лицензирование реально не работает, если дело касается меня — люди в любом случае будут использовать менее строгую из двух лицензий. Различные запреты, которые предлагает GPL, бессмысленны, если люди могут просто выбрать пользование под менее ограничивающей лицензии типа Apache. Поэтому имело смысл просто использовать менее ограничивающую из двух лицензий.
Если вы посмотрите вокруг, нет особо значительных GPL-нутых языков сценариев. Под GPL-нутыми я имею в виду строго идущими лишь под GPL. Perl — двулицензионный с полностью неограничивающей художественной лицензией. Python имеет собственную лицензию. Ruby двулицензионный со своей лицензией. Tcl распространяется под лицензией BSD-типа. Не вижу, почему то, что PHP не распространяется под GPL, расстраивает кого-либо.
...реально GPL не нужна. Для меня не проблема, если Майкрософт забросит ASP и полностью перейдёт на PHP. Безусловно, они могут принять и расширить его, но в таком случае мы будем с ними в чисто технической гонке. Это битва, которую мы можем выиграть, и, наконец, иметь PHP везде было бы классной штукой для PHP-сообщества.
PHP сегодня
SP: К чему бы вы приписали успех PHP? Чувствуете ли вы, что PHP имеет какое-либо особое слабое место (в сравнении с другими языками)?
RL: Людям нравится PHP, потому что он решает их веб-задачи. А раз так, я не вижу какого-либо слабого места. Он делает работу, для которой был разработан.
Кое-кто может приводить довод, что определённые аспекты PHP не так развиты, как в других языках. Для примера — поддержка ООП. Но в конечном счёте оно мало нужно для решения задач веба, а скорее для эстетики и стремлении к чистоте языка.
SP: Вы по-прежнему активно вовлечены в развитие PHP?
Я всё ещё достаточно вовлечён. Я не трачу 20 часов в день, как делал это в первую пару лет, но по-прежнему устраняю ошибки, спорю с другими разработчиками по поводу деталей и порой вскакиваю и вставляю лишний новый кусочек тут и там.
SP: Какой веб-сервер лучше всех поддерживает PHP? Apache или какой-то ещё? И на какой платформе лучше всего работает PHP? Линукс/Интел, Солярис/SPARC или другая?
RL: Полагаю, всё сводится к тому, какая получает наибольшее внимание. Большинство людей используют Линукс/Интел с Apache. Это значит, что ошибки на этой платформе находятся самими разработчиками быстро, и маловероятно, что конечный пользователь столкнётся с чем-то, с чем ещё не сталкивались разработчики. Другие платформы Юникс-мейнстрима, такие как Солярис/SPARC и FreeBSD/Интел с Apache так же находятся в их числе.
SP: PHP обычно бывает спаренный с MySQL. Насколько много две команды сотрудничают в области разработок?
RL: Мы знаем ребят из MySQL очень хорошо. Первый код для базы данных в PHP был написан для предшественника MySQL, который назывался mSQL. Интерфейс к MySQL, когда он появился, был полностью совместим с интерфейсом mSQL, так что с самых первых дней существования MySQL PHP хорошо поддерживал его. Эта пара работает потому что PHP и MySQL имеют обыкновение выбирать минималистический и очень прямой подход к решению проблем.
С точки зрения сотрудничества на уровне разработки — такого в действительности немного. Но много и не требуется. PHP предоставляет тонкий слой, который просто выставляет интерфейс MySQL пользователю PHP. Мы поставляем вместе с PHP клиента MySQL, но эта библиотека полностью поддерживается командой разработчиков MySQL с небольшим участием нашей — кроме моментов когда они меняют структуру, конечно же.
SP: Полагаете ли вы, что PHP становится заменой Perl?
RL: Нет, Perl — это язык сценариев общего назначения. PHP особенно привязан к проблемам веба.
SP: Какова ваша точка зрения на Magic Quotes* и Register Globals**?
Опция, включающая автоматическое добавление обратного слеша к кавычкам в данных, приходящих из форм и HTTP-запросов. В SQL-запросах текстовые строки выделяются кавычками. Чтобы вставить строку, содержащую в себе кавычки, их нужно выделить ("эскейпить") обратными слешами ("\"). Это делается либо при помощи функции addslashes, либо автоматически при включенной опции Magic Quotes (прим. переводчика).
** Данные из POST и GET запросов (и аналогично других типов источников) доступны в массивах $HTTP_POST_VARS, $HTTP_GET_VARS. Например, значение поля name из формы будет находиться в $HTTP_POST_VARS["name"]. Опция Register Globals делает данные из этих запросов доступными по "простым" именам переменных. В данном примере — $name (прим. переводчика).
RL: Register Globals — одна из особенностей, которая привела людей в PHP. Простота создания веб-приложений, когда форма и другие переменные были автоматически доступны не может быть побеждена.
Лично я не был за выключение опции Register Globals по умолчанию. Это очень мало увеличивает общую безопасность приложения. Если люди не проверяют данные, приходящие от пользователя, тогда и без, и с включенными Registered Globals это приложение будет небезопасным.
Иметь отключенные Register Globals полезно только в одном случае — когда вы забываете инициализировать переменную до её использования, и кто-то, кто знает ваш код, использует это. Меняя уровень сообщений об ошибках, вы можете дать PHP найти эти случаи автоматически. В итоге, я думаю, всё, что сделало отключение Register Globals — это усложнило написание приложений на PHP.
И ещё это сделало нам 10-20 вопросов/сообщений об ошибках в день от пользователей, которых сбило с толку это изменение.
Magic Quotes произошли в те дни, когда PHP использовался в основном исключительно для приложений, работающих на базах данных. Эти программы принимали данные из формы и вставляли их в базу. Даже сегодня куча скриптов на PHP делают чуть больше этого.
Вам всё время нужно эскейпить кавычки перед тем, как вставлять строку в базу данных. Если вы этого не делаете, вы получаете уродскую ошибку SQL, и ваша программа не работает. После объяснения этого простого факта людям в пятидесятый раз на дню я решил, что с меня хватит, и заставил PHP эксейпить строки на лету. Таким образом, программы будут работать, а худшее, что может произойти — это кто-то увидит лишний обратный слеш ("\") на экране, когда они выводят данные напрямую вместо вставки их в базу.
Часто люди даже не замечают лишний \, поскольку это не вызвало фатальных ошибок SQL, и поэтому меня не приводят в замешательство письма с вопросами, что же происходит. Это было очень здорово.
Даже сегодня вы можете увидеть случайный сайт, где, очевидно, автор не осознавал, что данные нужно эскейпить перед вставкой в базу, и вы видите то тут, то там \. Каждый из этих сайтов — это письмо на саппорт, на которое нам не нужно было отвечать.
Информированные люди, которым не нравится эта фича, могут отключить её сами и управляться со всеми кавычками самостоятельно. А информированные, которые хотят писать компактные программы, могут просто проверить настройки, используя get_magic_quotes_gpc() и добавить вызов addslashes(), где нужно.
SP: Как вы полагаете, успешен ли баланс между коммерческим элементом и элементом открытого кода PHP?
RL: Я думаю, оно работает нормально. Различные коммерческие объекты заставляют индивидов работать над частями PHP — а это выгодно всем.
SP: Что было наиболее удивительным в инновационном использовании PHP, которое вы видели в интернете?
RL: Я продолжаю смотреть новые и причудливые вещи, последняя из которых — это ActiveScript SAPI модуль Уэза Фарлонга (Wez Furlong), который позволяет вам делать PHP-скрипт для клиентской стороны:
<html>
  ...
  <script language="ActivePHP">
    function clickit() {
      $GLOBALS["window"]->open("http://www.php.net");
    }
  </script>
  ...
  <img src="..." onclick="clickit();" />
</html>
PHPMole IDE для PHP Алана Ноулеса (Alan Knowles), написанный в PHP-GTK — также достаточно впечатляющий. Есть много других классных вещей на PHP в Сети, но эти, возможно, самые последние из того что я собирался делать.
Будущее PHP
SP: Существуют ли планы по серверным переменным с состоянием (кумулятивным переменным) в PHP? Было бы полезно поместить шаблонные объекты в разделяемую память, чтобы пользователям не приходилось бы подвергаться большим накладным расходам из-за обявления классов.
RL: Проект Альтернативного PHP Кэша (Alternative PHP Cache, APC) уже может держать шаблонные классы в разделяемой памяти, так что проблема была решена APC и другими.
Лично я полагаю, если у вас есть проблемы ресурсоёмкости, вам нужно либо немного упростить код, либо взяться за написание критических частей на C. Расширение PHP на уровне C в действительности намного легче, чем большинство людей думает.
SP: Нынешние "сессионные" переменные используют дисковое пространство (например, /tmp), что не очень хорошо для сайтов с высоким трафиком. Есть ли планы исправить это?
RL: С первого дня поддержки сессий в PHP мы обеспечили обработчик сессий для буфера в разделяемой памяти. Просто замените обработчик на mm вместо files в php.ini. Однако, для сайтов с высоким трафиком это не решение. Реальное решение — это балансировать нагрузку на сайте на нескольких уровнях.
Хранение данных сессии в памяти на одной машине не решит ничего. Для этого напишите свой собственный обработчик сохранения сессии и храните данные сессий в какого-либо рода центральной базе данных. Посмотрите руководство по функции session_set_save_handler.
SP: А что с пулингом коннектов к базам данных? Непрерывные (persistent) соединения не настолько хороши — есть ли планы применить пулинг соединений в будущем?
RL: Пул соединений должен управляться одним процессом. Поскольку большинство использует мультипроцессовый пред-разветвляющий сервер Apache, просто нет способа, которым PHP может делать пулинг соединений. Это должно осуществляться выделенным самостоятельным процессом, а это вне области самого PHP. И SQLRelay, и SRM* могут быть использованы для решения этой проблемы.
Когда общая архитектура для PHP будет однопроцессовом многопоточном веб-сервере, мы можем рассматривать помещение этой функциональности прямо в PHP, но до того дня это не имеет особого смысла. Даже Apache 2 — всё ещё будет многопроцессовым сервером, в котором каждый процесс будет способен держать в себе несколько потоков. Поэтому потенциально мы можем иметь пул соединений в каждом процессе.
SP: Есть ли планы улучшить ООП? Пользователи чувствуют, что должно быть меньше накладных расходов в шаблонных классах, и обеспечение инкапсуляции такое, что они могли бы прятать некоторые переменные. Есть ли планы по этому эффекту?
RL: Да.
SP: Sybase и MS SQL Server предоставляют поддержку многим наборам результатов, возвращённых из хранимых процедур SQL. PHP не поддерживает этого! Когда пользователи смогут ожидать этого?
RL: Когда кто-нибудь предложит код, делающий это.
SP: Сейчас запросы к базам данных буферизуются в памяти перед тем, как они будут доступны клиенту. Могут ли PHP-программисты ждать, что это поведение изменится, чтобы запросы были доступны немедленно, как только сервер базы данных присылает их?
RL: Могут, когда разные интерфейсы управления (API) базы данных будут поддерживать это. Мы уже поддерживаем это с MySQL через вызов mysql_unbuffered query().
SP: Zend Engine 2 планирует некоторые захватывающие новые фичи, такие как обработка исключений и развитая поддержка ООП. Можете ли вы дать нам грубую оценку, когда пользователи смогут ждать релиза — хотя бы в месяцах или годах?
RL: Нет. Он будет выпущен, как только будет готов.
SP: Видите ли вы будущее в PHP-GTK, с популярными настольными программами, написанными на PHP?
RL: Думаю, PHP-GTK в основном используется в случаях, где вам нужно обеспечить и веб-интерфейс, и GUI (графический пользовательский интерфейс — прим. переводчика) в одной программе. Возможность иметь один и тот же конечный код и для того, и для другого — большой выигрыш.
SP: Разработка PHP и Apache сейчас идут параллельно? Вероятно ли, что два проекта каким-либо образом сольются в один в будущем?
RL: PHP и Apache всегда были тесно связаны, поскольку оба являются кусочками головоломки, решающей проблемы веба. Поэтому есть некоторые разработчики, которые работают над обоими проектами. Но проекты определённо не сольются. В этом нет особого смысла.
SP: Думаете ли вы, что крупные корпорации будут использовать PHP в своих внутренних средах вместо J2EE и .NET в будущем?
RL: Некоторые используют, поэтому "да".
Заключение
SP: Что бы вы сказали молодым разработчикам, собирающимся начать свои собственные проекты Open Source?
RL: Я не уверен, что это возможно в этом смысле. Это что-то вроде сидеть и смотреть на свой телефон, ожидая, пытаясь заставить его зазвонить. Он всегда звонит тогда, когда вы в дУше, либо в другое неподходящее время.
Я не думаю, что вы действительно сядете и решите начать проект open source. Это "движение" — немножко миф, который люди любят возвеличивать и приписывать ему все виды нереальных черт. Никто не присоединится к вашему проекту, если всё, что у вас есть — это классная идея. У всех есть классные идеи.
Люди соберутся вокруг ваших усилий, если вы построите что-то, что достаточно полезно, что они решат, что проще взять ваш код и расширить его немного, чтобы решить их задачи. Если ваш хлам "недопечённый", люди, скорее всего, отклонят то, что вы сделали, и просто решат проблемы сами или используя что-то другое.
Поэтому чтобы начать проект open source, в первую очередь предположите, что вы действуете самостоятельно и решаете какую-либо проблему, с которая доставала вас некоторое время. Это значит многие месяцы работы, чтобы получить что-то на самом деле работающее и решающее проблему. В этот момент вы можете думать, стоит ли прекращать контроль и позволять другим присоединиться к вашим усилиям.
Ключевая фраза — "отказаться от контроля". Начало проект open source не значит, что вдруг у вас появится штат программистов, которыми вы сможете командовать. На самом деле, чтобы поднять это от земли вам нужно будет быть очень восприимчивым к предложениям от первых последователей и делать всё возможное, чтобы сделать ваш инструмент более полезным для более широкой публики. И затем вы откажетесь от всего этого и позволите людям делать что угодно с вашим кодом. Тогда вы начнёте проект open source.
SP: Какие другие инициативы open source вы запланировали? Что бы вы хотели сделать, имея бесконечное время (и 100 лишних пар рук)?
RL: Ну, я не планировал PHP. Я думаю, с точки зрения решения проблем, не с точки зрения программных проектов. На самом деле, я ненавижу программировать, но я люблю решать проблемы.* Итак, какие же проблемы я бы хотел решить, если бы я имел много времени и ресурсов?
"I actually hate programming, but I love solving problems".
Став недавно отцом, я имел большие планы построить "умную" детскую кроватку. Видео в прямом эфире, аудио и разные другие гэджеты, которые бы наблюдались и контролировались удалённо, чтобы позволить далёким друзьям и семье взаимодействовать с ребёнком. Конечно, как только ребёнок на самом деле появился, найти достаточно времени, чтобы просто сесть и почитать книгу, почти невозможно, не говоря о создании "умной" кроватки.
Другой действительно классный проект — исходная система построения дистрибутивов. Такая, где я мог бы указать, что у меня устройство с 486-м процессором, некоторым типом сетевой карты, и какие-нибудь специфики железа вместе с типом медиа и оперативной памяти, и эта штука сделала бы маленький дистрибутив Линукса предназначенный именно для моего устройства.
Затем, чтобы расширить это, иметь возможность сказать, что я хочу, чтобы оно работало как файрволл, mp3-сервер, броузерная станция. По существу добраться до точки, когда можно взять любое устройство и прицепить на него Линукс, и оно было бы работоспособным. У меня много устройств дома, которые, я знаю, можно улучшить в использовании, поставив на них более мощное ПО. И я бы хотел найти способ делать это без необходимости тратить по 6 месяцев на каждое.
Сообщество SitePoint и я хотели бы поблагодарить Расмуса за его потраченное время и детальные ответы нашим пытливым умам. Он может не контролировать силы за PHP, но он определённо блистает как член команды, которая работает вместе во всём мире, чтобы перевести PHP на следующий уровень.

среда, 23 января 2019 г.

Oracle и PHP - это очень просто!

Oracle и PHP - это очень просто!

Автор: Владимир Пржиялковский
Владимир Пржиялковский , преподаватель технологий Oracle
PHP – простое в употреблении, легкое и бесплатное средство для динамического построения страниц HTML на сервере, перед передачей клиенту в браузер. PHP умеет обращаться в СУБД Oracle, и это делает его хорошим кандидатом для разработки приложений web на основе Oracle малой и средней сложности.
Введение
СУБД Oracle, когда против желания фирмы-изготовителя, а когда согласно – в зависимости от направления политических ветров в конкретные периоды времени, – никогда, кроме начального периода своего существования, не была полностью закрытой системой. Например, с момента возникновения движения свободного ПО, разработки, ведущиеся открытым образом («открытыми текстами»), все время держали эту СУБД в зоне своих интересов. Когда некоторые представители такого ПО стали достаточно зрелыми, фирма Oracle, подобно другим крупным фирмам, «легализовала» связь своей СУБД с ними: ОС Linux входит в число стратегических платформ для Oracle, web-сервер Apache входит в состав штатной поставки; там же можно обнаружить следы Perl и Tcl, нашедших себе место во внутреннх процессах установки (OUI) и администрирования (OEM). Эти средства помогают организовать взаимодействие с Oracle вместо средств собственной разработки (например, Developer) или в дополнение к ним.
PHP принадлежит к числу средств открытого ПО, вполне состоявшихся, востребованность которых непрерывно растет (см. http://www.php.net/usage.php). PHP позволяет динамически формировать страницы HTML на сервере web. В этом качестве он занимает нишу, общую с Perl, Mason, Aquaruim (все – свободное ПО) и сервлетами (например, с JavaServer Pages). Сервером web может быть Apache, IIS или же еще несколько разновидностей. Здесь нам важно, что PHP умеет обращаться к СУБД Oracle и что это легкая и простая система.
Установка Oracle
Дальнейшие примеры будут приведены для включения поддержки Oracle в PHP. Можно использовать версию Apache со штатного установочного комплекта СУБД Oracle (в версии Oracle 10.1 – на Companion CD). Дежурное напоминание: для промышленного использования сервера web лучше все же взять последнюю версию Apache из сети, так как она более функциональна, надежна и защищена.
В Unix потребуется построить библиотеки программой make.
Найдите файл php.ini. Скорее всего он в каталоге c:\WINNT. Найдите параметр extension_dir и снимите комментарии (;) со строк:
; Расширение = php_oci8.dll
; Расширение = php_oracle.dll
; Расширение = php_dbase.dll
Последний параметр требуется раскомментарить только если вы намерены проиграть следующий далее пример с записью данных в формате dbf.
Копирование файлов динамических модулей
В соответствии с указанным в php.ini значением параметра extension_dir скопируем файлы:
переместить расширения \ php_oci8.dll корова
переместить расширения \ php_oracle.dll sapi
Перезапуск Apache и проверка
Осталось перезапустить Apache. Это можно сделать либо с помощью меню Start, либо через останов и запуск службы Windows. Если все проделано правильно, при запуске не будет ошибок.
Составим файл test.php:
<? php phpinfo (); ?>
Наберем в браузере адрес http://localhost/test.php. Если ошибок не имеется, значит модули *.dll для Oracle установлены правильно.
Посмотрим, как может выполняться обращение к данным в Oracle.
Работа с Oracle
Обращение с помощью PHP к данным в Oracle может осуществляться через CGI или через специальные функции. Первая возможность рискована с точки зрения безопасности и здесь не рассматривается.
Вторая, в свою очередь, реализуется двумя имеющимися библиотеками: php_oracle и php_oci8, из которых вторая считается более эффективной. Продемонстрировать ту и другую можно на примере файла employees.php:
<HTML>
<head> <title> Доступ к Oracle с php </ title> </ head>
<Тело>
<h3> Два типа доступа к Oracle из php: </ h3>
<? PHP
if ($ c = OCILogon ("скотт", "тигр", "orcl")) {
$ s = OCIParse ($ c, "выберите ename, sal from emp");
OCIExecute ($ s, OCI_DEFAULT);
while (OCIFetch ($ s)) {
echo "ename =". ociresult ($ s, "ENAME").
", Сал =". ociresult ($ s, "SAL"). "<br/>";
}
OCILogoff ($ с);
} еще {
$ err = OCIError (); эхо "Ошибка Oracle Connect". $ ERR [Текст];
}
?>
<Ч />
<? PHP
if ($ c = ora_logon ("scott @ orcl", "tiger")) {
$ curs = ora_do ($ c, "SELECT ename, sal FROM emp");
while (time_fetch ($ course)) {
echo "ename =". ora_getcolumn ($ curs, 0).
", Сал =". ora_getcolumn ($ curs, 1). "<br/>";
}
ora_logoff ($ с);
} еще {
эхо "Ошибка Oracle Connect". ora_error ();
}
?>
<Ч />
</ Body>
</ Html>
Обратимся по адресу Http: //localhost/employees.php.
Этот пример для наглядности упрощен, а в жизни нужно будет больше уделить места обработке ошибок и структуризации кода.
Вот пример вставки записи в БД. Данные передаются через строку запроса HTTP. Это позволяет организовать в приложении содержательный диалог, подключив средства ввода форм HTML.
Подготовим файл insert.php:
<HTML>
<head> <title> Доступ к Oracle с php </ title> </ head>
<Тело>
<h3> Пример INSERT: </ h3>
<? PHP
if ($ c = OCILogon ("скотт", "тигр", "orcl")) {
$ name = (строка) $ _ REQUEST ['empname'];
$ no = (int) $ _ REQUEST ['empno'];
$ query = "INSERT INTO emp (ename, empno) VALUES (: bind1,: bind2)";
$ s = OCIParse ($ c, $ query);
OCIBindByName ($ s, ": bind1", $ name);
OCIBindByName ($ s, ": bind2", $ no);
OCIExecute ($ s, OCI_DEFAULT);
OCICommit ($ с);
OCILogoff ($ с);
}
?>
Готово.
<Ч />
</ Body>
</ Html>
Поместим файл в htdocs и обратимся по адресу HTTP: //localhost/insert.php EmpName = Вася и EMPNO = 1111. В SQL*Plus или предыдущей страницей PHP можно проверить результат. Обратите внимание на то, что в приведенном примере никак не обрабатывается (а) блокировка строк, возможно мешающая вставке и (б) возможный конфликт первичного ключа.
Oracle, да не только
Как говорилось выше, PHP имеет функции обращения к данным отнюдь не только в Oracle. Наличие этих функций дает возможным использования этого инструмента достаточно экзотично, например для переноса данных между Oracle и другими системами. Например, нередко стоит задача переноса из формата dbf в БД под управлением Oracle или наоборот. Вот как ее можно решить «на коленке». Обратите внимание, что перенос инициируется из окошка браузера, а выполняется целиком на узле web.
Составим файл dbase.php:
<HTML>
<head> <title> Доступ с php к различным базам данных </ title> </ head>
<Тело>
<h3> Удаленная передача данных из Oracle в dbf: </ h3>
<? PHP
$ dbname = "c: /fromoracle.dbf";
$ def =
массив (
массив ("ename", "C", 10),
массив ("sal", "N", 7, 2)
);
$ dbid = dbase_create ($ dbname, $ def);
if (! $ dbid) echo "Не удалось открыть dbf."
?>
<? PHP
if ($ c = OCILogon ("скотт", "тигр", "orcl")) {
$ s = OCIParse ($ c, "выберите ename, sal from emp");
OCIExecute ($ s, OCI_DEFAULT);
while (OCIFetch ($ s)) {
$ rec [1] = ociresult ($ s, "ENAME");
$ rec [2] = ociresult ($ s, "SAL");
if (! dbase_add_record ($ dbid, массив ($ rec [1], $ rec [2])))
echo "Не удалось добавить запись.";
}
OCILogoff ($ с);
}
?>
Готово.
<Ч />
</ Body>
</ Html>
Обратимся по адресу: Http: //localhost/dbase.php. В корневом каталоге с: должен появиться файл fromoracle.dbf с данными, полученными из Oracle. Обратное преобразование можно проделать в качестве упражнения.
Таким же образом можно обращаться к mySQL, PostgreSQL, Sybase, SQL Server и другим системам управления данными и по ODBC.

Ловля ошибки в PHP

Ловля ошибок в PHP

Автор: Антон Довгаль
На серъезных сайтах странно видеть, когда ошибки выводятся пользователю в браузер в самых неожиданных местах. Почему они появляются - это отдельный разговор. Но почему они выводятся ? Ведь текст ошибок является информацией для дебага и предназначена для разработчика, а не для клиента.
Кроме того, именно эта служебная информация обычно помогает злым хакерам ломать сайт. В качестве классического примера можно привести вариант с выводом запроса при ошибке: "you have an error in query near WHERE id= "... Большое спасибо. Подставляем после "WHERE id=..." строку "0 OR 1>0" и запрос выполняется по всей таблице. Если запрос на удаление, то...сами понимаете, весело =). Поэтому я всегда переменные в запросах заключаю в кавычки. На всякий случай...
Но я увлекся. Сегодня не об этом. Сегодня поговорим о том, как избежать вывода ошибок клиенту, сохранив при этом все сообщения вебмастеру на память.
Начнем, пожалуй, с краткого обзора видов ошибок в РНР.
Таблица 1. Описания ошибок в PHP4 (оригинальный список)

Числовое
значение
КонстантаОписаниеЛовится/нет
1E_ERRORФатальные ошибки. Например, ошибка при обращении к памяти. Выполнение скрипта при этом прерывается.нет
2E_WARNINGПредупреждения (не фатальные ошибки). Выполнение скрипта не прерывается.да
4E_PARSEОшибки во время анализа синтаксиса. Генерируются парсером.нет
8E_NOTICEЗамечания (менее серьезные ошибки, чем предупреждения). Указывают на ситуацию, которая может стать причиной более серьезной ошибки, но могут случаться и в процессе нормальной работы скрипта.да
16E_CORE_ERRORОшибки во время загрузки РНР. Аналог E_ERROR, генерируется ядром РНР.нет
32E_CORE_WARNINGПредупреждения во время загрузки РНР Аналог E_WARNING, генерируется ядром РНР.нет
64E_COMPILE_ERRORФатальные ошибки во время компиляции кода. Аналог E_ERROR, генерируется зендовским движком.нет
128E_COMPILE_WARNINGПредупреждения во время компиляции кода. Аналог E_WARNING, генерируется зендовским движком.нет
256E_USER_ERRORПользовательская ошибка.да
512E_USER_WARNINGПользовательское предупреждение.да
1024E_USER_NOTICEПользовательское замечаниеда
Нас интересуют те ошибки, которые мы можем перехватить. К ним относятся: E_WARNING, E_NOTICE и E_USER_*. Остальные виды ошибок перехвату не поддаются либо из-за того, что происходят они еще до окончания загрузки самого ядра РНР, либо из-за того, что происходят на этапе синтаксического анализа и компилирования РНР-кода, поэтому их вывод придется просто отключить:
ini_set('display_errors',0);
Но я предполагаю, что наши скрипты достаточно отлажены, чтобы в них не было элементарных синтаксических ошибок, поэтому потерять мы ничего не должны.
По умолчанию уровень ошибок в РНР имеет значение E_ALL & ~E_NOTICE (или 2039 в числовой форме), что означает, что мы пропускаем мимо ушей замечания, но сообщаем о всех остальных ошибках.
Кстати, сами разработчики рекомендуют включать на стадии разработки и E_NOTICE - помогает обнаружить потенциально опасные места.
Поэтому изменим уровень вывода ошибок на E_ALL:
error_reporting(E_ALL);
Теперь переопределим хэндлер ошибок и подставим вместо него нашу функцию user_log(), которая и будет заниматься теперь обработкой ошибок:
set_error_handler('user_log');
Рассмотрим эту функцию подробней. Ей передаются 5 параметров:
  • код ошибки
  • текст ошибки
  • имя файла, в котором произошла ошибка
  • строка в файле
  • массив переменных
Возвращать эта функция ничего не обязана. Так как мы собираемся просматривать потом лог ошибок, то надо сделать запись лога, например, в файл так, чтобы нам потом было удобно с ним работать.
Итак, код с комментариями:
<?php

/* Наша функция-хэндлер */
function user_log ($errno, $errmsg, $file, $line) {
    // время события
    $timestamp = time();

    //формируем новую строку в логе
    $err_str = $timestamp.'||';
    $err_str .= $errno.'||'; 
    $err_str .= $file.'||';     
    $err_str .= $line.'||'; 
    $err_str .= $errmsg."\n"; 

    //проверка на максимальный размер
    if (is_file(LOG_FILE_NAME) AND filesize(LOG_FILE_NAME)>=(LOG_FILE_MAXSIZE*1024)) {
        //проверяем настройки, если установлен лог_ротэйт,
        //то "сдвигаем" старые файлы на один вниз и создаем пустой лог
        //если нет - чистим и пишем вместо старого лога
        if (LOG_ROTATE===true) {
            $i=1;
            //считаем старые логи в каталоге
            while (is_file(LOG_FILE_NAME.'.'.$i)) { $i++; }
            $i--;
            //у каждого из них по очереди увеличиваем номер на 1
            while ($i>0) {
               rename(LOG_FILE_NAME.'..'.$i,LOG_FILE_NAME. '.' .(1+$i--));
            }
            rename (LOG_FILE_NAME,LOG_FILE_NAME.'.1');
            touch(LOG_FILE_NAME);
        }
        elseif(is_file(LOG_FILE_NAME)) {
            //если пишем логи сверху, то удалим 
            //и создадим заново пустой файл
            unlink(LOG_FILE_NAME);
            touch(LOG_FILE_NAME);
        }
    }

    /*
    проверяем есть ли такой файл
    если нет - можем ли мы его создать
    если есть - можем ли мы писать в него
    */
    if(!is_file(LOG_FILE_NAME)) {
        if (!touch(LOG_FILE_NAME)) {
            return 'can\'t create log file';
        }
    }
    elseif(!is_writable(LOG_FILE_NAME)) {
        return 'can\'t write to log file';
    }
    
    //обратите внимание на функцию, которой мы пишем лог.
    error_log($err_str, 3, LOG_FILE_NAME);
}

?>
Весь код вы можете посмотреть тут или взять все в архиве.
Можно было бы, конечно, использовать более логичное для таких целей хранилище - базу, но ведь ошибки, в большинстве своем, возникают именно при работе с базой, поэтому я бы на нее не полагался.
Собственно, это все. Остальное, я думаю, не составит для вас труда, особенно, если пользоваться функциями file(); & explode();. А если все-таки составит, то вы можете воспользоваться [вот этим кодом].
Предвидя вопрос "почему я не использовал CSV, который, казалось бы, логично использовать в этой ситуации?", отвечаю: сообщения об ошибках могут содержать неизвестное количество служебных символов (ака запятых и точек с запятой), что явно затруднило бы разбор CSV. Да и не собираюсь я просматривать лог в Экселе.
Еще разные мысли на эту тему:
  • при устаревании лога gz'иповать файл и складывать его в архив;
  • то же, но с посылкой на почту;
  • при возникновении критических ошибок - слать мэйл (см. пример из мануала по функции set_error_handler);
  • для мазохистов можно использовать при этом XML.
Вздохнули спокойно? Я надеюсь, что нет. Ибо переопределение еррор-хэндлера - это никак не панацея, просто одна из удобных фич РНР.
Кто предупрежден, тот защищен - так ведь?
ps Признаю, немного параноидален. Но лучше два раза проверить, чем один раз сделать ошибку.
ps2 По просьбе Maxim Naumenko добавляю комменты к статье:

Q: Ну и чем это лучше, чем просто в php.ini указать error_log = "log_file.log" ?

A: Файл пишется в нашем формате. Нам же потом этот файл смотреть надо. Плюс - можно делать что угодно с этими ошибками (файл - это просто для примера). А в случае с error_log = "" - они ТОЛЬКО пишутся в файл и ничего более. Да и не везде вас пустят к php.ini.

вторник, 22 января 2019 г.

Время выполнения SQL запросов

Время выполнения SQL запросов


Итак, нам нужно засечь время, потраченное на выполнение SQL запросов ? Это не очень легко, но и не сложно. Начнем с определения задачи. Необходимо выдать полное время, затраченное на генерацию страницы и время, затраченное на выполнения SQL запросов, еще было бы здорово вывести процент от общего времени.
Сначала напишем функцию, которая выдает время, затраченное на выполнение своего кода:
функция do_something ()
{
$ mtime = microtime ();
$ mtime = explode ("", $ mtime);
$ mtime = $ mtime [1] + $ mtime [0];
$ tstart = $ mtime;
// здесь код для выполнения
//.........
$ mtime = microtime ();
$ mtime = explode ("", $ mtime);
$ mtime = $ mtime [1] + $ mtime [0];
$ тендер = $ mtime;
$ tpassed = ($ тендер - $ tstart);
возврат ($ tpassed);
}
Для конкретно нашей задачи, нужно модифицировать эту функцию так, чтобы выполнялись SQL запросы:
//запрос передается как аргумент
функция do_query ($ query)
{
//подсоединяем две глобальные переменные
глобальный результат в $;
глобальный $ qnum;
//счетчик запросов
$ Qnum ++;
//засекаем время старта
$ mtime = microtime ();
$ mtime = explode ("", $ mtime);
$ mtime = $ mtime [1] + $ mtime [0];
$ tstart = $ mtime;
//выполняем запрос
$ result = MYSQL_QUERY ($ query);
//засекаем время окончания
$ mtime = microtime ();
$ mtime = explode ("", $ mtime);
$ mtime = $ mtime [1] + $ mtime [0];
$ тендер = $ mtime;
$ tpassed = ($ тендер - $ tstart);
//возвращаем время, затраченное на запрос
возврат ($ tpassed);
}
Теперь у нас есть функция, которая считает запросы и выдает время экзекуции :) Вот как она должна быть использована:
//Не забудьте где-нибудь в начале скрипта объявить эти две переменные:
$ Результат = 0;
$ Qnum = 0;
//...
//Вызов функции:
$ sql_time + = do_query ("SELECT * FROM SOME_TABLE");
//Теперь можно разбирать полученные данные:
while ($ row = mysql_fetch_array ($ result))
{
печать ($ строки [ 'Текст']);
}
В окончательном скрипте нужно еще засечь полное время выполнения, таким же способом, что использовался в функции. Внизу код такого скрипта, который заработает, если вы вставите реальные SQL запросы и подсоединитесь к базе данных.
<?
//Засекаем время старта
$ mtime = microtime ();
$ mtime = explode ("", $ mtime);
$ mtime = $ mtime [1] + $ mtime [0];
$ tstart = $ mtime;
//Коннектимся к базе:
включите 'connect.php';
//Объявляем переменные
$ Результат = 0;
$ Qnum = 0;
//Объявляем нашу функцию
функция do_query ($ query)
{
глобальный результат в $;
глобальный $ qnum;
$ Qnum ++;
$ mtime = microtime ();
$ mtime = explode ("", $ mtime);
$ mtime = $ mtime [1] + $ mtime [0];
$ tstart = $ mtime;
$ result = MYSQL_QUERY ($ query);
$ mtime = microtime ();
$ mtime = explode ("", $ mtime);
$ mtime = $ mtime [1] + $ mtime [0];
$ тендер = $ mtime;
$ tpassed = ($ тендер - $ tstart);
возврат ($ tpassed);
}
//Далее тело скрипта
$ sql_time + = do_query ("SELECT * FROM SOME_TABLE");
//Обрабатываем данные
while ($ row = mysql_fetch_array ($ result))
{
печать ($ строки [ 'Текст']);
}
//Пример еще одного запроса
$ sql_time + = do_query («ВЫБРАТЬ * ИЗ ДРУГОГО»);
//Обрабатываем данные
$ row = mysql_fetch_array ($ result);
печать ($ строки [ 'Another_Text']);
//Засекаем время окончания
$ mtime = microtime ();
$ mtime = explode ("", $ mtime);
$ mtime = $ mtime [1] + $ mtime [0];
$ тендер = $ mtime;
$ total = ($ тендер - $ tstart);
//Выдаем время:
printf("SQL запросов: $qnum, время mysql: %f, всего затрачено: %f секунд !", $sql_time, $total);
//Вычисляем процент времени:
$ sqlpercent = ($ sql_time * 100) / $ всего;
print('Процент времени на MySQL: '. round($sqlpercent, 2) . '%');
?>
Вот и все ! :)