Pull to refresh

Comments 108

Работу через прокси прикрутите, полезная штука для «рутинной работы».
Хорошо, попробую. Единственное, что не быстро — работы много.
Теперь есть, хотя и примитивный.
Попробовал.
Будет удобнее, если будет в наличии дефолтная конфигурация.
В принципе, некоторые параметры в конфиге можно сейчас просто не указывать, скрипт сам их подставит. Но наверное действительно будет правильней сделать конфиг по умолчанию. Спасибо за подсказку, подумаю.
Теперь при инициализации можно вообще не отдавать конфиг.
А какая проблема в получении HTTP статусов, все делается через CURL: CURLOPT_HEADER => true
Вы же обвертку сделали, и там как-то HTTP заголовки получаете, так нет проблемы сделать strpos($header,«404 Not Found») например.

А функциональность вся из CURL проброшена в классы? Например поддержка curl_multi_getcontent есть?
curl_getinfo($ch, CURLINFO_HTTP_CODE);
Ну вот тем более! Если бы CURL был в ООП сразу сделан (как, например, PDO), то я бы предпочел сделать к нему API обвертку сделать (процедурную или в виде статического класса). Ведь проще наприсать $content = curl::getPage($URL); чем создавать объект, потом вызывать метод, потом разрушать.
Смотря что вы подразумеваете под api, мне кажется тут достаточно обычной функции, принимающе список параметров. Зачем усложнять простые вещи?
Ну под API я тут понимаю набор функций как раз, сгруппированный или файлом или пространством имен или статическим классом. Для получения страниц или кравлера это самое удобное, ни каких объектов и событий, классов и синглтонов тут разводит не нужно.
А вот кстати, может подскажете, в каком виде их лучше всего будет кидать и на какие именно операции?

А то я думал на эту тему, но так что-то ни до чего структурированного не додумался. Сделал просто $Snufkin->request->error, в который кидаю курловую ошибку, если что-то вдруг не так.

Буду рад идеям/предложениям.
Ну вот во всех тех местах где вы пишете в ->error делайте
throw new SnufkinException($message, [$code]);

Ну и свой класс ексепшена добавить:

class SnufkinException extend Exception {}

Кстати архитектурно можно много всякого улучшить.
Сделать например отдельные классы Snufkin_Request и Snufkin_Responce

Ну и добавить возможность делать chain-вызовы, типа:
$Browser->get_request_send('http://facebook.com')->response_charset_change('utf-8', 'windows-1251')->dump_get();
Про последнюю возможность не знал, спасибо. Насчет остального подумаю.
>> свой класс ексепшена добавить
>> классы Request и Responce
>> chain-вызовы

ещё транспорты и будет копия Zend_Http_Client )
Один из принципов ООП, которым я руководствуюсь — это методы выдают либо объект (данные), либо exception. По умолчанию никаких null-ов и false-ов.
Лучше бы повторили функционал и синтаксис php.net/http для тех, у кого хостинг не позволяет ставить экстеншны.
А пока у вас ООП ради ООП, да еще и менее функциональное, нежели сам курл.
рациональность использования ООП для CURL вообще сложно понять, разве что делать chain ну и exeption кидать, в остальном не вижу смысла.
Ну какбы это вопрос более обширный: Для чего использовать ООП в принципе?
Ну и ответ я думаю вы знаете.

Ну и сомнения в целесообразности тут лишние, посмотрите на Zend_Http_Client
Пишут же люди для чего-то? Значит задачи есть.
Если у браузера (того же Firefox) стоит какой-то плагин типа Яндекс-бара, то юзер-агент будет подкорректирован (поправьте если я туплю). И Ваше тогда определение юзер-агента идет гулять :)
А, все. Вроде разобрался. Простите :)
UFO just landed and posted this here
Вроде того. Только Снупи работает, в основном, на сокетах. Однако тот же механизм общения через хттпс он все равно реализует через Курлу.
Zend_Http_Client же есть. Умеет всё то что умеет Снусмумрик + умеет прокси + бросает эксепшены, имеет адаптер для работы через CURL или сокеты. Я не пробовал и могу ошибаться, но вроде работает с https. И вообще более авторитетен. Пожалуй, единственный минус — это монструозность.
Вот скажите, пожалуйста, что вы подразумеваете под монструозностью?
То что он инклюдит внушительное кол-во файлов и тянет за собой пачку зависимостей. Например, мне не нужен весь ZF, я хотел использовать только Zend_Http, но пришлось так же сохранить Zend_Uri, Zend_Date, Zend_Validate, потому что они все ему нужны.

Причём я не спорю с тем что всё грамотно раскидано по файлам/классам. Мне нравится Zend. Но у него очень много возможностей, которые мне не нужны.

Кроме того, почему-то на некоторые УРЛы он бросает эксепшны, как на не валидные, хотя в браузере они открываются нормально.

Ну и ещё для тривиального использования он не подходит. Там где можно написать file_get_content() в случае использования Zend_Http пришлось бы написать 10 строк кода.
Просто положите один раз весь Zend в свою библиотеку и не мучайтесь.

И, пожалуйста, не рассказываейте, что он занимает много места на вашем хостинге!
Я и не рассказываю. Монструозность у него есть — это факт и это единственный его маленький минус. Из-за этого, я не буду использовать Zend_Http когда можно обойтись простым file_get_contents().

А зачем мне в моей папке Zend если я его не использую?
Если не используйте, то конечно незачем. А если используйте, то не нужно пытаться выдрать один компонент со всеми зависимостями.
я думаю логично использовать фреймворк там где он нужен весь. Если вам надо один процент — напишите его сами. Радость фреймворка как раз в том что вы используете его на все 100%. Я использую зенд целиком и меня не парит что он тянет зависимости потому что они мне нужны.
Написать самому HTTP клиент с Cookie_Jar, Proxy, редиректами и ещё расшифровывающий ответ если указан http-encoding??? Нееее, лучше я возьму Zend_Http.

Но зачем мне Zend_Db, Zend_Acl, Zend_Cache и десятки других не нужных мне пакетов? Конечно можно было бы не заморачиваться, но я предпочёл выкинуть всё не нужное. Это лучше чем писать свой недовелосипед.
так я и не против. просто тогда принимайте как должное подтягивание кучи зависимостей. Если не будет зависимостей — представьте какой обьем дублирования кода будет между компонентами, ведь тогда валидаторы и прочий код придется реализовывать буквально в каждом компоненте — а зенд все же больше фреймворк чем набор компонент
Мне откровенно непонятно, зачем люди публикуют топики со своими недовелосипедами?
Ну написал ты обертку для curl'a. Потренировался, закрепил материал. Но зачем публиковать это, если есть гораздо более лучшее и удобное решение. Я еще не упомянул, что оно хорошо документировано и спроектировано!? Вы понимаете, что им пользуются множество людей, а не только вы?!
И, да, кроме вышеописанного Zend_Http_Client поддерживает работу с защищенными соединениями, отслеживает редиректы, поддерживает куки, загрузку файлов, да много чего!

Вы говорите «это монструозность». Ну во что вы имеете ввиду? 10 — 20 файлов — это монструозность? Взамен на богатый ф-л в одном флаконе?

silkleo, изучите уже наконец-то фреймворк, с набором высокоуровневых инструментов и пользуйтесь на здоровье!
Спасибо за добрый совет.

Зенд фреймворк, равно как и его класс для работы с урлами, я в свое время достаточно ковырял, чтобы не испытывать никакого желания использовать этого слона на своих микропроектах. 90% его функционала мне не нужно. Также я ковырял Снуппи и еще пару схожих проектов, ссылки на которые не смог дать в топике, ибо просто потерял.

Моя цель была — сделать что-то карманное, простое и узкоспециализированное.
А с какой целью вы это опубликовали?
Ответ на ваш вопрос содержится в топике. Могу даже абзац сверху отсчитать, мне не сложно.
Мне тоже непонятно, зачем люди публикуют топики со своими недовелосипедами. В этом и был смысл моего коммента.
Ответ на ваш вопрос содержится в топике. Могу даже абзац сверху отсчитать, мне не сложно.
Для моих микропроектов не нужен громадный слон под названием Зенд. Хотя вообще Зенд мне нравится и я ничего против этого фреймворка не имею.

Возможно, в моем случае, проще было бы создать пачку методов и свойств для работы с курлой в классе «паука». Но помимо аггрегатора комиксов у меня еще есть аггрегатор IRC-логов в формате Эггдропа. И еще пара схожих штуковин. Копипастить в них один и тот же код я счел не комильфой. Писать единого «паука» для них и вовсе невозможно из-за довольно разных подходов к добыванию контента для разбора.

Вот почему на выходе получился все-таки отдельный модуль.
UFO just landed and posted this here
Многопоточность в CURL уже есть встроенная: curl_multi_init(), curl_multi_add_handle(), curl_multi_getcontent(), curl_multi_exec(), curl_multi_close()
UFO just landed and posted this here
И я бы даже не сказал, что стабильно, мы ее плотно юзаем, так крашается процесс пару раз в неделю, без всяких генераций эксепшенов, просто вылетает или подвисает.
UFO just landed and posted this here
Я бы советовал углубляться не в функционал, а в удобство.
Очень длинные имена, естественно (надеюсь) это сделано для удобства и понимания что происходит, но есть запросы которые итак интуитивно понятны:
$browser->get(...); // вместо $Browser->get_request_send(...)
Либо на крайняк $browser->get($params)->send(); // удобно, гибко, изменяемо
Как вараинт разбить на типы: $browser->request->get(...); $browser->response->clear(); (clearBody)
Как ни крути, повторяя один в один вы сделаете тот же самый курл но со стрелочками =) А нужно сделать качественную и удобную библиотеку, которая инкапсулирует курл, это не одно и то же. Бейте на классы, разжелите запрос и ответ, не бойтесь сделать длинней, дайте возможность переопределять любую часть вашей библиотеки, подумайте над апи и удобством пользования и будет Вам счастье. Сейчас это копия курла в виде обьекта. ООП — не набор функций в классе, это не стоит забывать.
Все что вы описали, включая короткие алиасы и тд — в планах. Я над этим думаю и постараюсь воспользоваться большей частью дельных советов, полученных в комментариях. Единственное, не могу обещать, что это произойдет быстро. Работы много.

Но в любом случае спасибо.
А вот так неудобно?

$client = new Zend_Http_Client(/*uri*/, array(/*http params*/));
$response = $client->request(/*method. default is GET*/);
Зендовский клиент гибкий, это именно то что я говорил «Бейте на классы, разжелите запрос и ответ, не бойтесь сделать длинней, дайте возможность переопределять любую часть вашей библиотеки». В зенде запрос разбит на несколько классов, это дает возможность использовать каждый по отдельности, и переопределить любую часть, это удобно, это практично и гибко. В данном же случае только один класс.
У меня была как раз мысль сделать «одну коробочку», в которую подаешь урл и пару параметров, или просто урл, а оно тебе что-нибудь там отвечает. Отсюда и такая архитектура.
UFO just landed and posted this here
UFO just landed and posted this here
UFO just landed and posted this here
Лучше сделать хоть что-то, услышать гору критики и повернуть в нужное русло, чем вообще ничего не делать
UFO just landed and posted this here
Почитайте каменты, там есть критика, дайте свою критику, но не в духе «да что за говно тут запостили», а конструктивную. И будет всем счастье, Вы укажите недостатки и сделаете доброе дело, автор увидит свои ошибки и и попытаеся исправить.
UFO just landed and posted this here
UFO just landed and posted this here
Не важно знаю я пхп или нет, я просто не люблю каменты в стиле «все говно, автор уг итд», возможно так же как и вы подобные топики =)
Кстати класс пригодится при условии что вывод придется фильтровать в будущем ;)
UFO just landed and posted this here
Приведите список неудобств. Кроме уже упомянутых невозможности работать с хттпс и через прокси.
UFO just landed and posted this here
То есть от диалога вы отказываетесь?
UFO just landed and posted this here
UFO just landed and posted this here
UFO just landed and posted this here
А мне вот нравится загонять в классы/объекты с нужным мне интерфейсом функции многих стандартных библиотек PHP. Да, оверхид, но если так код пишется и читается проще, то пускай будет оверхид.

В оправдание могу сказать, что если вдруг, например, в качестве HTTP-клиента cURL не устроит, то могу заменить только реализацию класса HTTP-клиента на, скажем, собственную, работающую напрямую с сокетами, но с тем же интерфейсом, или соответствующий класс ZF обернуть — остальной код менять не нужно будет. А если ещё DI реализовать, то вообще только конфиг какой-нибудь. Но это в теории, на практике ни разу менять реализацию не приходилось. Вообще это отмазка — на самом деле мне просто нравится скрывать детали реализации и ООП для этого мне нравится больше, чем процедурный подход.
UFO just landed and posted this here
Укажите в параметре 'cookies' конфига полный путь к тому месту, где будет лежать джар-файл, включая имя файла, и куки заработают. У меня во всяком случае получалось и залогиниваться на закрытые сервисы, и прочие разности творить.
UFO just landed and posted this here
вот я и говорю — что не хватает,
+ надо реализовать парсинг строчки и выбор нужной куки
Куки автоматически разбираются в объект $Snufkin->response->head->cookies, откуда их можно легко доставать при необходимости. И сохраняются в файл, если путь к нему указан в настройках.
Опять же, если файл в настройках указан, класс скормит его Курле, а Курла уже сама разберется, куда и чего ей отдавать при запросе.
UFO just landed and posted this here
UFO just landed and posted this here
UFO just landed and posted this here
Можно ссылку на агрегатор комиксов? Кажется догадываюсь о каких сайтах идет речь, действительно неудобно прыгать по закладкам, а руки все не доходят что-то предпринять.
Там Furry-комиксы. Не знаю, про них ли вы подумали.

Ссылка вот: www.silkleo.ru/comix/html/twenty/

«html» в урле можно заменить на rss или atom, чтобы получить соответствующий формат.
А не, ошибся ) Ладно, значит руки все-таки дойдут. Все равно спасибо.
Товарищ nalimka, хватит исходить на желчь. Любой разработчик на PHP когда-нибудь писал свои обертки к Curl и MySQL. Писать их самому, в сравнении с использованием фреймворков, может быть полезно по нескольким причинам:

— во-первых, ZF, хоть и хороший и известный фреймворк, но при этом уродливый монстр. Тянуть чуть ли не полгигабайта файлов ради того, чтобы отправить 1 GET-запрос — верх маразма. Эти файлы, мало того, что напрасно занимают место на диске, еще и СИЛЬНО увеличивают потребление памяти и время, которое PHP тратит на их загрузку и разбор (в случае использования кешера они еще и в нем дофига памяти отъедают). Возможно, некоторым недопрограммистам, пришедшим с Явы и нравится для каждой задачи порождать сотни файлов по 10 строчек, и каждую селочь делать через абстрактные фабрики, но это все же сказывается на производительности. Плюс, там много лишнего хлама, типа транспорта, который работает через fsockopen() вместо curl. Если у вас на хостинге нельзя ставить курл — купите за 70 рублей в месяц VPS в селектеле и хоть на C# там код пишите.

— во-вторых, менее монструозные штуки типа Snnopy или httpClient — недоделанные, несовершенные, часто устаревшие (PHP 4 живее всех живых), неэффективные. Пишет их обычно кто попало. Если можно написать лучше, почему бы и нет.

— в-третьих, полезно для собственного развития и лучшего понимания например HTTP-протокола.

Я сам например, написал аж 2 обертки над курлом: Util_Curl — для самых примитивных вещей (get/post), и обертку с многопоточным скаичиванием, проксями, ограничением частоты запросов, автоматическим перекодированием кодировок, разбором HTTP Response headers, ручной работой с куками, коллбеками, преобразованием УРЛов в абсолютный вид. ZF такое вряд ли умеет, плюс моя обертка состоит из 3 файлов, а не тонны кода.

Так что, уважаемый автор, пишите дальше, а этот код все же спрячьте куда нибудь и никому не показывайте, пока не перепишете нормально.

Что касается вашего кода, то во-первых, методы с подчеркиваниями смотрятся ужасно, во-вторых, 6 аргументов к функции — это маразм и нечитабельно, в-третьих, имхо, лучше использовать конструкторы в виде статических методов, а не безликий несемантичный бессмысленный new. Советую поменять интерфейс на такой:

$page = Snufkin::init($options)->getBody('http://example.org', $getData, $requestOptions);
$code = Snufkin::init($options)->get('http://example.org', $getData = array(), $requestOptions = array())->getHttpCode();
$code = Snufkin::init($options)->post('http://example.org', $postData, $requestOptions)->getHeader('Location');

Ну и перекодировку, рефереры, response_clean() (ручное управление памятью??) и прочую ненужную хрень уберите куда-нибудь в опции.
Почему параметры в функции — маразм? Особенно учитывая, что обязательный параметр там один — это урл.
1. У меня не было задачи переносить весь функционал Курлы в ООП.

2. Подчеркивание в именах методов в большом объеме ИМХО кода читаются гораздо лучше, нежели конструкции вроде $this->myMethodName();. Впрочем, это вкусовщина и холиворить я на эту тему не собираюсь. Равно как и менять этот синтаксис.

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

4. Если не затруднит, поделитесь, пожалуйста, ссылками на свои обертки. Я их вывешу в топике в разделе «Альтернативы», чтобы другие люди могли выбрать ваши скрипты для своих нужд.
UFO just landed and posted this here
Кстати, насчет изучения HTTP-протокола вы абсолютно правы. После написания этого модуля я намного лучше стал понимать принципы его работы.
UFO just landed and posted this here
UFO just landed and posted this here
— во-первых, ZF, хоть и хороший и известный фреймворк, но при этом уродливый монстр. Тянуть чуть ли не полгигабайта файлов ради того, чтобы отправить 1 GET-запрос — верх маразма.

ZF v1.11 — 23.2 MB

— во-вторых, менее монструозные штуки типа Snnopy или httpClient — недоделанные, несовершенные, часто устаревшие (PHP 4 живее всех живых), неэффективные. Пишет их обычно кто попало. Если можно написать лучше, почему бы и нет.

Лучше, чем Zend_Http_Client, ок!

— в-третьих, полезно для собственного развития и лучшего понимания например HTTP-протокола.<.blockquote>
Выше я написал «Ну написал ты обертку для curl'a. Потренировался, закрепил материал. Но зачем публиковать это, если есть гораздо более лучшее и удобное решение.»

Эх, держите меня семеро, пока я свои разработки на хабр не запостил.
UFO just landed and posted this here
О ноу. Нельзя такие прекрасные имена тянуть в скучную среду программинга. Должны быть вещи, не запятнанные ассоциями с работой. Я вас ненавижу.
У меня еще Хаттифнатт есть. Хе-хе.
вот и выросло поколение, которое среди готового не ищут первым делом в pear
посмотрите PEAR::HTTP_Request2
Смотрел и Зенд, и Пир когда писал этот модуль. Уже пять раз в комментариях написал, что не нужны мне эти слоны под мои микропроекты.

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

кстати, слон — для данного класса звучит очень неоднозначно. да, в нём исходников много, но зато сам бегает быстро за счёт внутренней оптимизации, возможности параллельных обработок и т.д. вот здесь есть обсуждения phpclub.ru/talk/threads/%D0%BF%D0%B5%D1%80%D0%B2%D1%8B%D0%B9-%D1%80%D0%B5%D0%BB%D0%B8%D0%B7-pear-http_request2.57389/
Первый коммент в топике жжет напалмом. Хотя его автор, конечно, не прав.
Какой смысл использовать COOKIE FILE, если его отлично можно получить/собрать/отправить простой строкой.

Регулярки для примера:
/Set-Cookie:\040(.+?)(\n|$)/is — получение
/((expires|path|domain)=.+?|secure|httponly|\S+=deleted)(;|$)/i — фильтрация
А зачем делать за Курлу то, что она и сама прекрасно умеет делать?
Рефакторить надо, наверное, долго и упорно:) Только открыл — и у меня уже вызывает вопросы например этот участок кода
function
      __construct($conf = false) {
        $conf = array(
          'timeout'  => 5,
          'redirects' => 2,
          'agent'   => 'Snufkin 4.0',
          'referer'  => 'http://github.com/Shushik/Snufkin/',
          'charset'  => 'utf-8',
          'encoding' => 'gzip/deflate',
          'ssl'    => array(),
          'headers'  => array(),
        );

        if ($conf) {
          // Change default config values
          foreach ($conf as $alias => $value) {
            $conf[$alias] = $value;
          }
        }

* This source code was highlighted with Source Code Highlighter.


Дело в том, что $conf сразу же переопределяется. Что, такое и правда будет работать??
При передаче в параметрах $conf лучше делать null, чем false. Хотя в данном случае, при переопределении параметров, задающихся массивом, и ожидаться должен пустой массив. И естественно, нет никакой нужды заново изобретать array_merge :)) А сами параметры по умолчанию — членом класса, чтобы их в случае необходимости можно было быстро менять или использовать в других методах.

Конструктор лучше сделать public, а название метода не переносить ёлочкой на следующую строку — таких гайдлайнов я нигде ещё не видел. Ну и по именованию — $conf всё же это традиционные $params (реже $options).
Итого с учётом сказанного выглядеть это должно примерно так:

protected $defaultParams = array(
      'timeout'  => 5,
      'redirects' => 2,
      'agent'   => 'Snufkin 4.0',
      'referer'  => 'http://github.com/Shushik/Snufkin/',
      'charset'  => 'utf-8',
      'encoding' => 'gzip/deflate',
      'ssl'    => array(),
      'headers'  => array(),
    );

    public function construct($params = array()) {
        $params = array_merge($this->defaultParams, $params);


* This source code was highlighted with Source Code Highlighter.


Касательно именований методов: методы cookies(), charset(), headers(), header(), head(), headы(), http(),… etc — абсолютно неясно из названий, что они делают. Методы — по определению глаголы, а не существительные. То есть set_cookies() намного более понятно, чем просто cookies(). Ведь установка далеко не единственное возможное действие с ними.

Остальной код не смотрел.
Всё вышеописанное отправил пулл-реквестом github.com/Shushik/Snufkin/pull/1
Прошу прощения за опечатку, конечно же, __construct. В репозитории тоже исправил.
Огромное спасибо! И как я упустил такое…
Sign up to leave a comment.

Articles

Change theme settings