- Перестали работать запросы в WordPress, что делать?
- Почему мы видим ошибку certificate has expired?
- Решение ошибки: cURL error 60: SSL certificate has expired
- Вариант 1
- Вариант 2
- HTTP API WordPress
- Короткое знакомство с HTTP API
- Функции HTTP API и отправка запроса
- Функции отправки запросов:
- Функции получения ответа на запрос:
- Параметры функций
- Примеры запросов на базе WordPress HTTP API
- #1 Передача параметров запроса в GET и POST
- #2 Изменение настроек запроса
- #3 Получение тела ответа (наше любимое)
- #4 Получение заголовков ответа
- #5 Получение кода ответа
- #6 Произвольный тип запроса
- #7 Получение данных о фильме с Кинопоиска
- Сохранение результата запроса (кэширование)
- Кэширование во временные опции (transients)
- #1 Примеры кэширования HTTP запроса во временную опцию
- Удаление временной опции
- Кэширование в метаполя
- #1 Примеры кэширования HTTP запроса в метаполя
Перестали работать запросы в WordPress, что делать?
C 30 сентября 2021 года на сайтах WordPress, для которых был установлен сертификат Let’s Encrypt, могут перестать работать HTTP API запросы.
Например такой запрос будет выдавать ошибку:
cURL error 60: SSL certificate problem: certificate has expired
Такую ошибку можно будет увидеть где угодно, например:
- в админке при проверке обновлений WordPress
- при проверке обновлений плагинов
- при обращении к апи любого сервиса. Например, перестанет работать плагин TinyPNG — JPEG, PNG & WebP image compression и куча других, которые используют какие бы то ни было запросы.
Почему мы видим ошибку certificate has expired?
Почему так происходит подробно расписано на хабре.
Если коротко, то в ядре WP есть файл корневых сертификатов /wp-includes/certificates/ca-bundle.crt который используется для проверки SSL всех запросов созданных через HTTP API. В этом файле просрочен один из корневых сертификатов на основе которого был создан сертификат для вашего сайта. Поэтому запрос не может пройти проверку и выдается такая ошибка.
С очередными обновлениями WP эта ошибка должна пропасть, но вот что делать если решение нужно уже сегодня, или если вы не планируете обновлять WordPress, а рабочие HTTP запросы нужны.
Решение ошибки: cURL error 60: SSL certificate has expired
Вариант 1
Нужно обновить контент файла /wp-includes/certificates/ca-bundle.crt изменить его на контент этого файла https://curl.haxx.se/ca/cacert.pem.
Изменять в данном случае файл ядра допустимо, потому что при следующем обновлении WP проблема исчезнет. См. соответствующий коммит на GitHub.
Это можно сделать вручную:
- Скачайте файл по ссылке https://curl.haxx.se/ca/cacert.pem.
- Обновите контент /wp-includes/certificates/ca-bundle.crt контентом из скаченного файла.
Или используйте следующий код
Использовать код удобно, когда у вас есть возможность запустить код из админки или как-то еще, например через плагин Code Snippets.
Добавьте следующий код куда угодно и перейдите на страницу http://ВАШСАЙТ.com/?update-wp-ca-bundle .
После использования, код нужно удалить.
Вариант 2
Решить проблему можно через хук http_request_args. Этот хук нужно использовать в MU плагине.
Создайте файл loader.php в папке wp-content/mu-plugins (если такой папки у вас нет, создайте её).
Добавьте следующий код в этот файл:
Создайте папку wp-content/mu-plugins/fix-wp-ca-bundle .
Создайте файлы: main.php и ca-bundle.crt в папке fix-wp-ca-bundle .
Добавьте следующий код в эти файлы.
Код файла main.php :
Контент файла ca-bundle.crt :
Должна получится такая структура:
Готово! Теперь все должно работать как и прежде.
Источник
HTTP API WordPress
В PHP есть несколько способов отправить HTTP запрос, в WordPress только один. Но этот один способ включает в себя все варианты поддерживаемые PHP — это и есть API, это стандарт и это удобно!
Короткое знакомство с HTTP API
Для совсем новичков, пожалуй стоит пояснить, что такое HTTP запрос. Это запрос браузера к серверу, или одного сервера к другому, где происходит подобный диалог:
- Привет сервер, можешь мне показать файл: file.html?
- Привет! Могу, вот он.
Выглядит такой диалог вот так (только на месте клиента в данном случае выступает наш сервер, который делает запрос на другой сервер):
При создании HTTP запросов в PHP, как правило используются один из вариантов: библиотека cURL или встроенные в PHP потоки (streams). Чтобы упростить и стандартизировать разные способы отправки запросов, с версии 2.7. в WordPress появился класс WP_Http, который и лег в основу HTTP API.
С версии WP 4.6 ядро WP_Http полностью заменили PHP библиотекой Requests for PHP и теперь все запросы выполняются через нее. Вышеупомянутые классы WP_Http_Curl и WP_Http_Streams уже не используются. Таким образом, технически HTTP API WordPress кардинально изменился, но остался прежнем внешне: все работает как и работало. Также, с внедрением библиотеки Requests ожидаются новые возможности, некоторые из них уже появились (нечувствительные к регистру заголовки, поддержка международных доменов вроде böcean.ch), а другие (параллельные запросы) появятся в следующих релизах и пока возможны только с использованием библиотеки Requests напрямую.
Устарело с WP 4.6. WP_Http определяет тип транспорта, и вызывает другой класс соответствующий этому типу. Вызванный класс создает сам запрос. По умолчанию в WordPress два таких класса, для разных типов: WP_Http_Curl и WP_Http_Streams
Удобство и необходимость такого API заключается в том, что разные хостинги поддерживают разные варианты отправки запросов, а некоторые не поддерживают ни один. Задача HTTP API создать единый стандарт использования запросов в WordPress, при этом чтобы запросы работали всегда, если не поддерживается один способ транспортировки запроса, то будет найден альтернативный.
Другая задача — упростить разработку. Авторам плагинов приходится писать кучу кода, изобретать велосипеды и допускать ошибки. И все это, чтобы их плагин умел работать с любым хостингом. С HTTP API эта задача должна упроститься до нескольких встроенных в WordPress функций.
Еще один плюс HTTP API в том, что мы имеет единый стандарт указываемых данных, при работе с разными типами транспортировки запросов, т.е. мы всегда указываем одинаковые параметры и передаем их в функцию HTTP API, а класс уже выбирает подходящий тип транспорта, например cURL, изменяет наши параметры под понятные для текущего типа транспорта, и отправляет запрос.
С версии 2.7. HTTP API работал только с базовыми элементами запроса: header , body и response . С версии 2.8. появились: сжатие (compression), куки (cookies) и поддержка прокси (proxy). Некоторые из функций пассивные, т.е. работают автоматически, без установки дополнительных параметров запроса.
HTTP API WordPress сегодня — это полноценное API, в котором учтены многие мелочи и исправлены сотни ошибок. Также следует заметить, что до версии WP 4.4 HTTP API значительно отличался от того какой он сейчас, поэтому некоторые моменты из этого мануала могут не работать на версиях до 4.4.
Почти все возможности транспорта, можно изменять через опции или фильтры. Например, через фильтр http_api_transports можно добавить еще один, свой класс транспорта. Или через установку констант в файл wp-config.php можно включить режим прокси:
Чтобы разобраться, как работает прокси смотрите класс WP_HTTP_Proxy<>
Ну, и наконец, HTTP API можно без особого труда расширить, для работы с Twitter API, Google Maps API и т.д.
Функции HTTP API и отправка запроса
Использовать HTTP API очень просто, для этого существуют специальные функции API:
Функции отправки запросов:
wp_get_http_headers( $url ) — получает только HTTP заголовки указанного URL.
wp_remote_request( $url, $args ) – отправляет запрос любого типа: GET, POST, HEAD, PUT, DELETE.
wp_safe_remote_request( $url, $args ) — то же что и wp_remote_request() , но еще и позволяет избежать небезопасных редиректов и переадресаций. Нужно при HTTP запросах на заранее неизвестные URL, например, когда URL передается пользователем. Для «safe» также есть функции обёртки:
Все функции возвращают: массив или WP_Error.
- Результат возвращается в виде массива и содержит все данные ответа: контент (тело) ответа
- WP_Error возвращается в случае неудачного запроса. Если сервер вернул нестандартную ошибку: 500, 404 и т.д., то вы получите данные ответа, а не WP_Error..
Функции получения ответа на запрос:
wp_remote_retrieve_header( $response, $header ) — получает отдельный заголовок, где $header — имя заголовка.
wp_remote_retrieve_response_code( $response ) — получает HTTP код ответа (статуса ответа). Такой код должен быть 200, если все в порядке. В случае ошибки статус будет 4xx или 3xx при редиректах. Полный список статусов смотрите в описании status_header()
wp_remote_retrieve_response_message( $response ) — получает сообщение ответа соответствующее коду ответа (статусу ответа). Например при статусе «200», сообщение будет «OK».
wp_remote_retrieve_cookie( $response, $name ) — получает все данные указанной куки, где $name — это название куки.
Параметры функций
Теперь, когда мы знаем все функции запросов, давайте попробуем создать простой запрос.
Тут, мы отправили запрос на URL: http://httpbin.org/get и добавили два параметра запроса ?a=b&c=d . В результате, $response будет содержать следующий массив:
Как видно, результат содержит ключи, каждый ключ — это часть ответа сервера, где:
- headers — содержит заголовки HTTP ответа сервера.
- body — тело ответа. Если мы запрашиваем html страницу, то тут будет HTML код. Если возвращаются JSON данные, то тут будет JSON строка. И т.д.
- response — содержит статус код HTTP ответа. Например 200 — OK.
- cookies — содержит куки, которые просит установить сервер в ответе на запрос.
- filename — содержит расположение или путь файла который был отправлен на сервер и был там размещен. Файл можно отправить POST запросом.
- http_response — с версии WP 4.6. Cодержит весь объект результата запроса библиотеки Requests.
Каждую часть ответа можно получить выбрав её из массива. Например, давайте получим заголовки ответа:
Однако, получать части ответа таким образом не рекомендуется! Потому что ответ может быть разный и его нужно проверить или как-то дополнительно обработать.
Для получения каждой части ответа рекомендуется использовать специальные функции указанные выше. Давайте получим нужные нам заголовки ответа правильно:
На этом теоретическую часть HTTP API можно закончить и перейти к практике, точнее к примерам.
Примеры запросов на базе WordPress HTTP API
#1 Передача параметров запроса в GET и POST
Для GET запроса аргументы передаются в самом URL:
Для POST запроса параметры передаются в настройке body :
#2 Изменение настроек запроса
Перед отправкой запроса, можно изменить дефолтные настройки запроса. Например, установить timeout (максимальное время) соединения или указать user agent.
Полный список параметров (настроек) смотрите в описании wp_remote_request().
А этот пример демонстрирует, как передавать такие настройки:
#3 Получение тела ответа (наше любимое)
Этот пример показывает как передать в запрос дополнительный заголовок и получить тело (текст) ответа.
#4 Получение заголовков ответа
#1 Делаем полный запрос и получаем из него заголовки
Этот пример показывает как сделать полный запрос, но получить только заголовки ответа:
#2 Запрашиваем только заголовки
В этом примере мы не будем создавать полный запрос, а запросим только заголовки. Для этого воспользоватся функцией запроса wp_remote_head() :
Ответ на такой запрос мы получим быстрее, чем при «полном запросе». Поэтому, если вам не нужно тело ответа, то пользуйтесь таким запросом.
#3 Запрашиваем только заголовки (способ 2)
Используя функцию wp_get_http_headers() , мы также можем не создавать полный запрос, а запросить и сразу получить только заголовки:
2 и 3 пример, никогда не содержать тело ответа и их использование может пригодится для высоко-нагруженных API, которые ограничивают число запросов в период времени. Так, перед тем как получить тело запроса, нужно проверить: а были ли изменены данные, отвечает ли сервер на наш запрос и т.д. В таких случаях, рекомендуется сначала отправить HEAD запрос, обработать ответ, где проверить есть ли новые данные и только потом делать полный запрос с получением тела ответа.
#5 Получение кода ответа
#6 Произвольный тип запроса
Кроме GET и POST типов запросов, мы можем отправлять любой другой, например, PUT или DELETE.
Для этого используем функцию wp_remote_request(), которая лежит в основе всех функций запросов:
#7 Получение данных о фильме с Кинопоиска
Этот пример показывает, как получить данные фильма с Кинопоиска, по указанному ID фильма.
Сохранение результата запроса (кэширование)
Кэшировать результат HTTP запроса нужно всегда, исключений, пожалуй, не бывает.
Очень важным моментом является кэширование результата — сохранение его куда-нибудь. Важно это, потому что без кэша, страницы сайта будут генерироваться медленно. Чтобы осознать всю важность кэширования, нужно понять, как все происходит и почему HTTP запросы будут тормозить загрузку страницы.
Дело в том, что при использовании одной из функций HTTP API наш сервер отправляет запрос на другой сервер и ждет ответа. В период ожидания, никакие PHP операции на нашем сервере не происходят — он просто останавливает выполнение скрипта и ждет. Такое ожидание может быть довольно долгим. Как правило, такое ожидание длится от 0,5 до 5 секунд.
Картина выглядит примерно так: нам на сервер пришел HTTP запрос: http://example.com/page , и наш сервер должен показать страницу page . Для этого наш сервер начинает генерировать эту страницу, при этом до выполнения каких либо операций по генерации страницы, подключаются различные модули: nginx, apach, PHP, модули PHP и т.д. Затем начинается генерация страницы, и чем сложнее страница, тем дольше она будет генерироваться. Но при этом, сервер использует свои данные из оперативной памяти, с диска, с базы данных и т.д. все эти данные он получает за доли секунды. А теперь представим, что в какой-то момент сбора данных и генерации страницы, нужно получить данные с другого сервера. В этот момент собирается запрос и отправляется, и наш сервер ждет ответа: пока запрос дойдет до другого сервера, пока там соберутся все модули, пока страница (ответ) сгенерируется и пока он вернется к нам через все узлы интернет соединения. Все это по меркам сервера, очень долго — от 0,5 до 5 секунд. А что если таких запросов несколько, например для данных в какой-нибудь таблице?
А теперь, ответе сами себе, нужно ли сохранять данные запроса на свой сервер, где он может получить их за доли секунды?
Другая проблема: «пропускная способность»
Теоретически можно обойтись без кэширования, если у вас на странице всего один HTTP запрос и сервер обрабатывающий этот запрос позволяет отправлять ему неограниченное количество запросов. Но как правило, если вы используете какой-то API, на сервере где обрабатываются запросы, стоит ограничение на количество запросов в промежуток времени, так называемая «пропускная способность» API. И в какой-то момент, удаленный сервер просто не ответит на ваш запрос, а вы не получите нужных данных.
На основе всего вышесказанного можно сделать единственно правильный вывод — кэшировать HTTP запросы нужно всегда, а сделать это совсем не сложно.
Кэширование во временные опции (transients)
Итак мы отправили запрос, получили результат и теперь нам нужно его сохранить. Вариантов куда сохранять результат много. Например, мы можем записать результат в файл и в следующий раз брать его от туда, или можно сохранить результат в базу данных. Но это потребует дополнительного кода, который, как правило не нужен, потому что в WordPress уже есть подходящие функции:
$transient(строка) (обязательный) Название временной опции. Максимальная длина 172 знака. Ожидаются данные с экранированными слэшами, очистка слэшей делается автоматически перед записью в БД. Функция автоматически защищает от SQL инъекций. $value(смешанный) (обязательный) Значение временной опции. Ожидаются данные с экранированными слэшами, очистка слэшей делается автоматически перед записью в БД. Функция защищает от SQL инъекций. Сериализация, если передается массив, также делается автоматически. $expiration(строка/массив/число/объект/логический)
Время жизни опции в секундах, начиная с настоящего момента. Например, чтобы записать опцию на один день, нужно указать 60 * 60 * 24 .
Если указать 0 — опция никогда не удалиться и не будет иметь срока давности. Получается это будет обычная опция, только с префиксом _transient_ в её названии — это будет означать, что она временная и при чистке таблицы wp_options её можно будет смело удалять, без риска, что-то испортить.
По умолчанию: 0
Важный момент про временные опции (transients). Они умеют работать с объектным кэшированием. Т.е. они записываются на время в базу данных wp_options . Но если на сайте установлен модуль (плагин) объектного кэширования, то они не записываются в БД, а сохраняются в файлы объектного кэша.
#1 Примеры кэширования HTTP запроса во временную опцию
Допустим, через HTTP запрос мы получаем курс рубля со стороннего сайта. Чтобы ускорить загрузку страницы, нам нужно кэшировать полученный результат на 12 часов.
Результатом работы этого кода, будет получение свежего курса доллара каждые пол дня.
Удаление временной опции
Допустим, вы уже не используете временную опцию и она не обновляется, и больше не нужна. В этом случае её лучше удалить. Временная опция сама по себе не удаляется и будет находиться в таблице wp_options до тех пор, пока вы не очистите все временные опции специальным плагином или как-то еще. Поэтому её рекомендуется удалить в ручную, если она уже не используется. Сделать это можно вызвав один раз такую строку:
Кэширование в метаполя
Для кэширования, временные опции подходят всегда, но не всегда это разумно. Для пояснения, представим такую ситуацию: у вас на сайте есть записи, допустим это фильмы и для каждого фильма вы парсите данные с внешнего источника, например, рейтинг Кинопоиска. Такие данные также нужно иногда обновлять, например раз в неделю.
В этом случае, будет логичнее сохранять полученные данные не в таблицу опций, а в метаполя записи. Потому что так их будет удобнее получать, мы получим возможность сортировать записи по рейтингу (по метаполю), к тому же это будет работать быстрее и грамотнее по коду. Потому что при установке параметра $expiration у временных опций, для их получения делается 2 простых запроса к базе данных, тогда как с метаполями WordPress работает гораздо эффективнее.
Но при использовании метаполей, вам нужно вручную проверять время жизни данных и обновлять их при необходимости. Время жизни данных можно записывать в схожее по названию метаполе. Кстати, во временных опциях в таблице wp_options делается тоже самое — создается временная опция и рядом еще одна опция с похожим названием и значением времени, когда опция устаревает.
#1 Примеры кэширования HTTP запроса в метаполя
Для примера, возьмем аналогию, где записи это фильмы и для получения данных фильма с Кинопоиска используется функция kinopoisk_get_movie( $id ) из примера выше. Также, предположим, что для каждой записи у нас уже есть ID фильма на Кинопоиске и находится он в метаполе kinopoisk_id .
Теперь, давайте напишем код для еженедельного обновления рейтинга каждого фильма. Для этого создадим функцию которая выводит рейтинг и одновременно проверяет не нужно ли обновить или получить данные:
Источник