пятница, 28 ноября 2008 г.

Регулярное выражение для проверки email адреса

Я думаю, многим приходилось сталкиваться с валидацией данных, введенных пользователем, при помощи регулярных выражений. Например, проверить корректность введеного email адреса. Сегодня нашёл регулярное выражение, которое используется именно для такой проверки  email адреса согласно RFC 2822, взято из исходников на Perl:

(?:(?:\r\n)?[ \t])*(?:(?:(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t]
)+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:
\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(
?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ 
\t]))*"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\0
31]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\
](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+
(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:
(?:\r\n)?[ \t])*))*|(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z
|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)
?[ \t])*)*\<(?:(?:\r\n)?[ \t])*(?:@(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\
r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[
 \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)
?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t]
)*))*(?:,@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[
 \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*
)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t]
)+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*)
*:(?:(?:\r\n)?[ \t])*)?(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+
|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r
\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:
\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t
]))*"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031
]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](
?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?
:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?
:\r\n)?[ \t])*))*\>(?:(?:\r\n)?[ \t])*)|(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?
:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?
[ \t]))*"(?:(?:\r\n)?[ \t])*)*:(?:(?:\r\n)?[ \t])*(?:(?:(?:[^()<>@,;:\\".\[\] 
\000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|
\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>
@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"
(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t]
)*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\
".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?
:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[
\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*|(?:[^()<>@,;:\\".\[\] \000-
\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(
?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)*\<(?:(?:\r\n)?[ \t])*(?:@(?:[^()<>@,;
:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([
^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\"
.\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\
]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*(?:,@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\
[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\
r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] 
\000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]
|\\.)*\](?:(?:\r\n)?[ \t])*))*)*:(?:(?:\r\n)?[ \t])*)?(?:[^()<>@,;:\\".\[\] \0
00-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\
.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,
;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?
:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t])*
(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".
\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[
^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]
]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*\>(?:(?:\r\n)?[ \t])*)(?:,\s*(
?:(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\
".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)(?:\.(?:(
?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[
\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t
])*))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t
])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?
:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|
\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*|(?:
[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\
]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)*\<(?:(?:\r\n)
?[ \t])*(?:@(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["
()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)
?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>
@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*(?:,@(?:(?:\r\n)?[
 \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,
;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t]
)*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\
".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*)*:(?:(?:\r\n)?[ \t])*)?
(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".
\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)(?:\.(?:(?:
\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\[
"()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])
*))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])
+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\
.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z
|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*\>(?:(
?:\r\n)?[ \t])*))*)?;\s*)

Не удивительно, что многие программисты испытывают сложности с написанием и пониманием регулярных выражений ;). Большинство не будет использовать приведенное выше регулярное выражение, собственно, как и я сам этого не делаю. В основном использую некоторое упрощённое выражение в своих проектах, и с ним, пока, не было проблем. Приведу пример регулярного выражения, взятый из моего PHP кода:

^[a-zA-Z0-9_\.\-]+@([a-zA-Z0-9][a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,6}$

Это выражение явно короче, но при этом оно не учитывает всех нюансов, заложенных RFC 2822. Для большинства нужд, будет хватать и этой регулярки, а что использовать - выбирать уже вам.

четверг, 27 ноября 2008 г.

5 аргументов не использовать inline CSS и JavaScript код

Если вы попали на мой блог, значит, вас интересует веб-программирование. Основой веб-программирования, понятное дело, является HTML, но никакой современный сайт уже не обходится без CSS и JS. В интернете можно встретить много разговоров о стандартах в web-программировании, в каком стиле лучше писать код. Ну а толку с них, - скажете вы, - если есть W3C, который занимается стандартизацией и там всё можно почитать. Конечно, можно, но там тонны информации, которую сложно переварить и надо затратить много времени на её изучение.

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

Итак, что же такое inline JavaScript и CSS, - это когда внутри html страницы идут вперемешку скрипты и описания стилей через строчку с html разметкой. Под JavaScript-ом вперемешку я понимаю не вызовы функций по событиям on_click, а непосредственно объявление этих самых вызываемых функций или объявление переменных между тегами <> < /script>, разбросанное по всей странице. Какая разница? – спросит большинство. А разница всё-таки есть, и я приведу вам 5 аргументов не использовать inline CSS и JavaScript код.


Аргумент 1: Кэширование и большинство оптимизаций не работают.
Большинство браузеров для убыстрения работы и уменьшения перегоняемого трафика используют в своей работе кэширование страниц. HTML страницы никогда не кэшируются. Что же касается графических изображений, внешних каскадных таблиц стилей (CSS) и файлов JS скриптов – то браузер пользователя наоборот, старается сохранить файлы в кэше при первом визите и при последующих запросах этих файлов не загружать их заново. Таким образом, объёмы загружаемой информации резко уменьшаются, перегружается только HTML-код страницы, а всё остальное подгружается из локального кэша браузера.

Аргумент 2: Непонятность кода и сложность нейтрализации ошибок
Допустим, у вас по большой HTML странице разбросаны JavaScript вставки. При наступлении какого-то события с неявно указанным обработчиком вам будет сложно выудить необходимый участок кода и нейтрализовать программные ошибки. А если страница компонуется из нескольких вставок, то обработчик и вовсе не будет отрабатывать, по той простой причине, что этот участок кода был случайно не включён.

Аргумент 3: HTML код становится тяжелее.
На выходе ваш HTML код получится значительно тяжелее и больше по объёму. HTML страница пронизанная JS и CSS вставками будет весить в килобайтах гораздо больше, чем аналогичная страница «чистая» по своей структуре.

Аргумент 4: Сложность модификации.
Лучше код взаимодействия вынести в одно централизованное место, чем просматривать весь текст в поисках однотипных участков кода для изменения, разбросанных по всем страницам сайта. Не каждый программист выдержит поддержку такого кода, разбросанного по всему сайту.

Аргумент 5: Невозможность повторного использования кода.
Если вы реализовали отличный по функционалу элемент интерфейса, то вы наверняка захотите его повторно использовать в остальных своих проектах. Но он намертво «вшит» по всем страницам сайта, и вам придется потратить уйму времени на его выуживание и прикручивание к другому сайту. При реализации, разнесенной по отдельным внешним файлам, всё, на что бы вам пришлось потратить время – это сделать подгрузку этих файлов, и вставить в необходимые места вызовы методов.

Надеюсь, мои 5 аргументов не использовать inline CSS и JavaScript код вас хоть немного убедили, и вы возьмёте их на заметку. Успешного кода, программист, и держи реализацию CSS и JavaScript в отдельных внешних файлах.

вторник, 25 ноября 2008 г.

Фотографии историко-культурного комплекса "Запорожская Сич"

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


Кстати, строительство историко-культурного комплекса "Запорожская Сич", как точной копии Сичи, существовавшей на о.Хортица, было начато ещё в 2004 году. Но в нашей стране деньги исчезают сразу после того, как их выделили, и вскоре работы прекратились из-за недостатка финансирования и возобновились лишь в июне 2005 года. На сегодняшний день, по некоторым данным, работы по созданию историко-культурного комплекса "Запорожская Сич" выполнены на 80-85 процентов. Вообще приятно видеть исторические памятки в нашем городе, жалко, что власти не хотят развивать идеи в направлении туристического бизнеса на должном уровне.

понедельник, 24 ноября 2008 г.

Странное дерево на о.Хортица


На этих выходных был на острове Хортица, в поле зрения попало вот такое симпатичное дерево. Так как я увлекаюсь фотографией, не удержался сфотографировать его. Под рукой приличного фотоаппарата не было, поэтому пришлось сфотографировать тем, что было (Sony DSC-80). В целом фото удалось, погода была пасмурной и шёл дождь, но от этого, контраста в фотографию только добавилось.

воскресенье, 23 ноября 2008 г.

Статус-коды ответов сервера (Server status-code responses)

В продолжение к предыдущему посту, где рассказывалось об особенностях использования cURL и передачи заголовков, приведу для справки статус-коды ответов сервера (server status-code responses).

[Informational 1xx]
100="Continue"
101="Switching Protocols"

[Successful 2xx]
200="OK"
201="Created"
202="Accepted"
203="Non-Authoritative Information"
204="No Content"
205="Reset Content"
206="Partial Content"

[Redirection 3xx]
300="Multiple Choices"
301="Moved Permanently"
302="Found"
303="See Other"
304="Not Modified"
305="Use Proxy"
306="(Unused)"
307="Temporary Redirect"

[Client Error 4xx]
400="Bad Request"
401="Unauthorized"
402="Payment Required"
403="Forbidden"
404="Not Found"
405="Method Not Allowed"
406="Not Acceptable"
407="Proxy Authentication Required"
408="Request Timeout"
409="Conflict"
410="Gone"
411="Length Required"
412="Precondition Failed"
413="Request Entity Too Large"
414="Request-URI Too Long"
415="Unsupported Media Type"
416="Requested Range Not Satisfiable"
417="Expectation Failed"

[Server Error 5xx]
500="Internal Server Error"
501="Not Implemented"
502="Bad Gateway"
503="Service Unavailable"
504="Gateway Timeout"
505="HTTP Version Not Supported"

Это структурированный список, уже готовый, для того чтобы его с лёгкостью можно было вставить в ini-файл или другой файл конфигурации. Он может использоваться для вывода более информативного сообщения, соответствующего индексу 'http_code' массива, возвращаемого функцией curl_getinfo().

Более информативный и детальный список по определению статус-кодов HTTP/1.1 можно получить на странице W3 консорциума http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html.

суббота, 22 ноября 2008 г.

Особенности использования cURL и передачи заголовков

Здравствуйте, читатели.

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

В данной статье хочу рассказать о библиотеке Libcurl. Libcurl — это кроссплатформенное программное обеспечение, библиотека, клиент использующийся для передачи URL. Она поддерживает огромное множество протоколов, таких как FTP, FTPS, HTTP, HTTPS, SCP, SFTP, TFTP, TELNET, DICT, LDAP, LDAPS и FILE. Так же libcurl поддерживает SSL сертификаты, HTTP POST, HTTP PUT, FTP загрузку, HTTP загрузку, основанную на формах, прокси, cookies, и многое другое. Пользователи могут довольно легко встроить её в свои программы при помощи API cURL. cURL действует как автономная обёртка для библиотеки libcurl. Для неё имеется более 30 различных привязок к языкам программирования, но я бы хотел показать механизм работы на примере PHP.

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

Немного почитав документацию по cURL, принялся писать код на PHP, ничего сложного в нём нет, приведу участок ниже.

< ?php
// ...

//если cURL доступен – то используем его
if ( (bool)function_exists("curl_init"))
{
  // создаём новый cURL resource
  $ch = curl_init();
  // выставляем соответствующие опции и требуемый URL
  curl_setopt($ch, CURLOPT_URL, $FILE_URL);
  curl_setopt($ch, CURLOPT_HEADER, 0);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  curl_setopt($ch, CURLOPT_BINARYTRANSFER, 1);

  // сделать запрос по URL и вывести в браузер
  curl_exec($ch);

// ...
?>


Перед использованием cURL нужно проверить присутствует ли вообще у вас данный модуль, поэтому следует использовать метод function_exists("curl_init"). Создав новый cURL resource и выставив необходимые опции (подробнее по каждой из них можно узнать здесь: http://php.net/manual/ru/function.curl-setopt.php) мы делаем запрос curl_exec и выводим ответ в браузер.

Запускаем скрипт на исполнение, проверяем на конкретной странице, выставляем параметр CURLOPT_URL равный http://webaurum.dev/index.php. И, о чудо, заработало! Мы получили результат исполнения страницы index.php. Так как мне нужен прокси для получения любого контента, решил проверить и на других видах содержимого, подставил jpg-файл. Задав в качестве запрашиваемого URL изображение http://webaurum.dev/image.jpg, но в ответ получил только каракули в окне браузера, вместо ожидаемой картинки.

Начал разбираться в чём же дело. Перехватив заголовки, получил следующее в Response Headers:

Date Fri, 21 Nov 2008 10:24:00 GMT
Server Apache/2.2.4 (Unix) mod_ssl/2.2.4 OpenSSL/0.9.8e DAV/2 PHP/5.2.3
X-Powered-By PHP/5.2.3
Expires Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma no-cache
Content-Type text/html
Keep-Alive timeout=5, max=100
Connection Keep-Alive


причём и для изображения и для скрипта php в заголовке Content-Type почему-то стояло text/html. Получается curl не передаёт ответ сервера в чистом виде, хотя и получает адекватно содержимое. В документации описана опция CURLOPT_HEADER, там сказано, что при установке этого параметра в ненулевое значение результат будет включать полученные заголовки. Включаем его, и заново проводим эксперимент, подав изображение на вход. В итоге в браузере увидел следующее:

HTTP/1.1 200 OK Date: Fri, 21 Nov 2008 10:24:01 GMT Server: Apache/2.2.4 (Unix) mod_ssl/2.2.4 OpenSSL/0.9.8e DAV/2 PHP/5.2.3 Last-Modified: Fri, 19 Sep 2008 14:23:29 GMT ETag: "4927-4b124-72007a40" Accept-Ranges: bytes Content-Length: 307492 Content-Type: image/jpeg ╪ р� JFIF� �H�H�� с �Exif��MM�*��� � � ���

… и дальше шла куча иероглифов. Как ни странно, но curl смог адекватно определить mime тип запрашиваемого содержимого (Content-Type: image/jpeg), и даже правильно сформировал заголовки. Тем не менее, в респонсе сервера и дальше красовалось Content-Type: text/html. Почему же не выставляются таким образом заголовки, если до того никакого вывода в браузер не было, для меня осталось загадкой.

Недолго думая, решил распарсить эти заголовки вручную, и установить их явно при получении ответа от curl. У библиотеки curl есть мощный механизм для получения технических аспектов отработки запроса – метод curl_getinfo. Он может принимать множество параметров, но нас, в частности, интересует ключ CURLINFO_HEADER_SIZE. При использовании этого ключа, метод возвращает длину заголовков в ответе curl_exec. Зная длину заголовков, можно вырезать их из общего содержимого, установить их явно при помощи функции header(), а потом уже вывести остаток содержимого в бинарном виде. Тогда браузер должен адекватно проинтерпретировать mime тип полученного содержимого. Код приведен ниже.

< ?php
// ...

//если cURL доступен – то используем его
if ( (bool)function_exists("curl_init"))
{
  // создаём новый cURL resource
  $ch = curl_init();
  // выставляем соответствующие опции и требуемый URL
  curl_setopt($ch, CURLOPT_URL, $FILE_URL);
  curl_setopt($ch, CURLOPT_HEADER, 1);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  curl_setopt($ch, CURLOPT_BINARYTRANSFER, 1);

  // сделать запрос по URL и вывести в браузер
  $data = curl_exec($ch);

  $headers = substr($data, 0, curl_getinfo($ch, CURLINFO_HEADER_SIZE));
  $data = substr($data, curl_getinfo($ch, CURLINFO_HEADER_SIZE));
  // парсим заголовки
  $headers = explode("\r\n", $headers);
  foreach ($headers as $header)
  {
  // устанавливаем каждую часть заголовка отдельно
  header($header);
  }
  // выводим остатки контента в браузер
  print($data);
  // закрыть cURL ресурс и высвободить системные ресурсы
  curl_close($ch);
}

// ...
?>


Теперь перехватим заголовки ответа сервера, и проверим результат:


Date Fri, 21 Nov 2008 11:12:49 GMT
Server Apache/2.2.4 (Unix) mod_ssl/2.2.4 OpenSSL/0.9.8e DAV/2 PHP/5.2.3
X-Powered-By PHP/5.2.3
Expires Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma no-cache
Last-Modified Fri, 19 Sep 2008 14:23:29 GMT
Etag "4927-4b124-72007a40"
Accept-Ranges bytes
Content-Length 307492
Content-Type image/jpeg
Keep-Alive timeout=5, max=100
Connection Keep-Alive

После запуска PHP скрипта на исполнение мы получили долгожданную картинку в окне браузера, а не набор иероглифов, как было раньше. При желании с помощью метода curl_setopt можно задать любые параметры запроса или передать точную копию cookie пользователя, таким образом, что между запросом пользователя и запросом сервера-посредника (прокси-сервера) почти не будет разницы.

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

Рекоммендую

Попробуйте надёжный хостинг от Scala Hosting