SSL из PHP: socket и cURL

    Сегодня, этим сонным летним утром, я расскажу вам про SSL соединение из PHP скрипта. Расскажу исходя не только лишь из теории, а ещё и решая вполне себе практическую задачу — логин на гугловский блогосервис blogger.com.

    Начнём с сокетов. В хелпе заявлена возможность использования HTTPS протокола, поэтому пробуем. Набор POST переменных взят из developer's guide. Хабрапарсер обрамляет мыло ссылкой, поэтому "@" заменена на (at).

    $postvars = array(
      "Email" => "mail(at)gmail.com",
      "Passwd" => "pass",
      "service" => "blogger"
    );

    $postdata = "";
    foreach ( $postvars as $key => $value )
        $postdata .= "&".rawurlencode($key)."=".rawurlencode($value);
    $postdata = substr( $postdata, 1 );

    $fp = fsockopen("ssl://google.com", 443);
    $send = "";
    $send .= "POST /accounts/ClientLogin HTTP/1.1\r\n";
    $send .= "Host: google.com\r\n";
    $send .= "Content-length: ".strlen($postdata)."\r\n";
    $send .= "Content-type: text/plain\r\n";
    $send .= "Connection: close\r\n";
    $send .= "\r\n";
    $send .= $postdata."\r\n\r\n";

    fputs($fp, $send);
    $html = fread($fp, 1000000);
    fclose($fp);

    echo "".$html."
    ";


    В функции fsockopen в качестве префикса перед именем сервера используем не https, а ssl. Так прямым текстом написано в хелпе. Дальше всё просто. Формируем HTTP-header, и пихаем его в открытый сокет. Читаем ответ, и получаем

    Error=BadAuthentication

    Короче, если опустить часовые мытарства и пляски вокруг функций сокета, у меня ничего не вышло. Ну то есть не вышло передать POST данные, хотя GET запросы возвращаются нормально. Может это связано только с гугловским сервером, а где-то в другом месте получится.

    UPD. Огромное спасибо хабраюзеру anabolik, который подсказал что если изменить одну строку заголовка и сделать
    $send .= "Content-type: application/x-www-form-urlencoded\r\n";
    то всё сразу заработает. Ещё раз спасибо. Отблагодарил всякими способами =).

    Переходим ко второму способу.

    Открываем страницу мана про cURL и радуемся. Столько возможностей для запросов, для всякого конфигурирования. Должно получиться. Итак, лезем в curl_setopt. Нам понадобятся
    CURLOPT_URL — это URL запроса.
    CURLOPT_POST — говорим, что будем посылать POST запрос.
    CURLOPT_POSTFIELDS — собственно POST переменыые.
    CURLOPT_RETURNTRANSFER — вернуть результат запроса, а не выводить в браузер.

    Теперь собственно о SSL параметрах:
    CURLOPT_SSL_VERIFYPEER — если поставить его в 0, то удалённый сервер не будет проверять наш сертификат. В противном случае необходимо этот самый сертификат послать.
    CURLOPT_CAINFO — указывать файл сертификата, если CURLOPT_SSL_VERIFYPEER установлен в 1.
    CURLOPT_SSLVERSION — целое число, указывает версию SSL (2 или 3), обычно определяется автоматически.
    CURLOPT_SSL_VERIFYHOST — будет ли производиться проверка имени удалённого сервера, указанного в сертификате. Если установить значение «2», то будет произведена ещё и проверка соответствия имени хоста. (если честно, я так и не понял что делает этот флаг)

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

    $postvars = array(
      "Email" => "mail(at)gmail.com",
      "Passwd" => "pass",
      "service" => "blogger"
    );

    $postdata = "";
    foreach ( $postvars as $key => $value )
        $postdata .= "&".rawurlencode($key)."=".rawurlencode($value);
    $postdata = substr( $postdata, 1 );

    $ch = curl_init();
    curl_setopt ($ch, CURLOPT_URL, "https://www.google.com/accounts/ClientLogin");
    curl_setopt ($ch, CURLOPT_POST, 1);
    curl_setopt ($ch, CURLOPT_POSTFIELDS, $postdata);
    curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
    curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
    $result = curl_exec ($ch);
    curl_close($ch);

    echo $result;


    В переменной $result у нас теперь находятся три строки, из которых нужна только одна — последняя, которая начинается с «Auth=». Но про это, наверное, в следующий раз.

    Это кросспост из моего блога.
    Поделиться публикацией

    Похожие публикации

    Комментарии 21
      +1
      в первом случае вроде надо добавить
      $send .= "Content-type: application/x-www-form-urlencoded\r\n";
      и должно заработать.
        0
        Да вы волшебник, сударь!
        Пойду подправлю тему.
        0
        если не затруднит подкиньте ктонибудь пример где происходит аунтификация по сертификату личному,как на light.webmoney.ru к примеру.
          +1
          давно писал этот скрипт щас уже не заню куда он делся, ну чтоб все это заработало я просто тупо проснифил общение броузера с веб сервером, ну собственно все эти заголовки что шлет броузер серверу, я послал скриптом как выше описано, вот и все...
            0
            Что-то подобное было в дипломе вот одна функция)
            function doConnect($method, $url, $cert, $cert_pass,$vars,$head) {
            $ch = curl_init();
            if($method == 'GET' || $method == '')
            curl_setopt($ch,CURLOPT_CUSTOMREQUEST,"GET");
            curl_setopt($ch,CURLOPT_URL,$url);
            curl_setopt($ch,CURLOPT_HEADER,1);
            curl_setopt($ch,CURLOPT_POST,0);
            curl_setopt($ch,CURLOPT_USERAGENT,"User-Agent=Firefox/2.0.14");
            curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
            curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,0);
            curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,0);
            curl_setopt($ch,CURLOPT_SSLCERT,"$cert");
            curl_setopt($ch,CURLOPT_SSLCERTPASSWD,"$cert_pass");
            if($head!=="")
            curl_setopt($ch,CURLOPT_HTTPHEADER,array("ClientSign: $head\n"));
            if ($method == 'POST') {
            curl_setopt($ch, CURLOPT_POST, 1);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $vars);
            }
            $answ = curl_exec($ch);
            curl_close($ch);
            print "\n\nAnswer from server:\n";
            print $answ;

            }
            +3
            Вместо конструкции

            $postdata = "";
            foreach ( $postvars as $key => $value )
            $postdata .= "&".rawurlencode($key)."=".rawurlencode($value);
            $postdata = substr( $postdata, 1 );


            Лучше использовать функцию http_build_query


            $postdata = http_build_query($postvars);
              +1
              Спасибо, не знал про такую.
                +1
                ну только если не нужна совместимость с php4
                "http_build_query
                (PHP 5, PECL pecl_http:0.1.0-0.9.0)" (c) the PHP Documentation Group
                0
                Такой весь из себя хакер, а элементарных вещей не знает:
                mail@gmail.com
                Код:
                mail@gmail.com.
                Хех, может написать yet another статью о том как писать посты на хабре) Ато есть еще замечания
                  0
                  Ни разу не сказал что я хакер. Просто влом было искать таблицу html сущностей. Зато всегда найдутся люди, которые только лишь для того чтобы подъебнуть человека готовы разрыть здоровенные справочники...
                    0
                    Эээээ.. у тебя мания величия))) Нафиг мне тебя под**ывать. Мне уже не 17 лет(к сожалению). По другому я тебе никак не мог это сказать, кстати все твои статьи на данную тематику плюсовал, и слово хакер написал без кавычек!!. А ты тут прям так стреманулся.. Тот кто хочет написать статью, вместо того чтоб писать, тупой хабрапарсер делает ссылку, пойдет и найдет решение. Если бы ты не акцентировал на этом внимание в статье, я бы не написал такой комментарий) Вообщем ты спровоцировал сча ненужный флуд с моей стороны.
                      0
                      Дык я вроде тоже без агрессии писал). А про спецсимвол — это природная лень =). Проще было пару строчек в пост докатать.
                        0
                        )) А мат? ) Ладно, проехали)
                  +1
                  кстати раз уже тут про курл - хочу заметить что курл не работает с фтп через сокс5 - может кто-то не знает еще...
                    –2
                    Детский сад какой-то...
                      +3
                      Человек, знающий, что такое сокеты - знает, что курл не может ничего такого, чего не может, допустим, телнет. Курл лишь предоставляет удобный интерфейс. А ошибка с контент-тайпом (специально для пионеров) - ничего общего с ХТТПС не имеет - точно так же "провалился" бы и запрос без ССЛ. И даже не "запрос провалился" - а просто запрашивающий не дал серверу понять, что в теле запроса придут данные из формы. А еще вдогонку, для тех же пионеров: когда пишете подобную программу - запрашивайте для начала свой собственный какой-нибудь скрипт, и только когда убедитесь, что запрос идет правильно и мог бы быть корректно обработан вашим скриптом - переходите к реальному УРЛу.
                        0
                        Пустой звук. От PHP'шных доков больше пользы.
                        Честно говоря, вообще не понял, зачем было рассматривать fsockopen в применении к HTTPS, так с протоколом походу только скрипт-кидди работают.
                          0
                          Когда формируете $postdat, проще использовать http_build_query().

                          CURLOPT_SSL_VERIFYHOST. Познал прелисти такой проверки в FF3. В сертификате указано для какого домена он действителен. Мы проверяем, действительно ли пренадлежит.

                          Присоединюсь к предыдущим ораторам — от манов пользы больше.
                            0
                            уже ни раз встречал данный пример в рунете… так что низачОт :(
                              0
                              Небольшой совет по использованию curl. Опции гораздо удобнее и более кратко передавать массивом, например:
                              $options = array
                              (
                              CURLOPT_URL => $url,
                              CURLOPT_HEADER => false,
                              CURLOPT_COOKIE => $cookie,
                              CURLOPT_RANGE => $start . '-' . $end,
                              CURLOPT_FILE => $fp
                              );

                              $ch = curl_init();
                              curl_setopt_array($ch, $options);
                                0
                                lists.whatwg.org/pipermail/whatwg-whatwg.org/attachments/20080714/07ea5534/attachment.txt

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

                                Самое читаемое