Wanet error log

Класс предназначен для удобного выполнения запросов — с помощью расширения curl, а также функций file_get_contents и fsockopen. Класс автоматически использует тот из доступных методов (транспортов) отправки запросов — расширение либо одну из перечисленных функций, — который доступен на сервере, выполняет проверку на наличие ошибок при получении ответа, а также возвращает содержимое ответа, раскодированное в соответствии с указанным форматом.

Класс предназначен для удобного выполнения запросов — с помощью расширения curl, а также функций file_get_contents и fsockopen. Класс автоматически использует тот из доступных методов (транспортов) отправки запросов — расширение либо одну из перечисленных функций, — который доступен на сервере, выполняет проверку на наличие ошибок при получении ответа, а также возвращает содержимое ответа, раскодированное в соответствии с указанным форматом.

Если вы считаете, что классу не хватает какой-либо объективно необходимой функциональности, оформляйте свои предложения в виде pull request в GitHub-репозитории фреймворка.

Порядок использования класса:

  1. Создать экземпляр класса, передав в него массив необходимых параметров.
  2. Если необходимо, вызвать «подготовительные» методы: cookies и userAgent.
  3. Для выполнения запроса вызвать метод query, который вернет содержимое ответа.
  4. Если необходимо, вызвать методы, возвращающие дополнительную информацию об ответе на запрос: getResponse и getResponseHeader.

Методы

  • cookies

    Устанавливает путь по умолчанию к файлу, содержащему cookies.

  • getResponse

    Возвращает содержимое последнего полученного ответа на запрос.

  • getResponseHeader

    Возвращает содержимое заголовков последнего полученного ответа.

  • query

    Выполняет запрос к указанному ресурсу.

  • multiQuery

    Параллельно выполняет несколько curl-запросов с функциями-обработчиками.

  • userAgent

    Устанавливает либо возвращает значение, которое будет использовано для заголовка «User-Agent«.

public function __construct ($options, $custom_headers = array())

Параметры

  • $options

    Массив параметров для подключения к удаленному ресурсу. Допустимые ключи массива:

    • format: формат ожидаемого ответа: waNet::FORMAT_JSON (JSON), waNet::FORMAT_XML (XML) либо waNet::FORMAT_RAW (простой, не требующий стандартной обработки)
    • charset: кодировка отправляемого запроса; значение по умолчанию: 'utf-8'
    • authorization: флаг, обозначающий необходимость авторизации с использованием заголовка Authorization
    • login: имя пользователя для авторизации
    • password: пароль для авторизации
    • md5: флаг, обозначающий необходимость указания содержимого запроса, обработанного функциями md5 и base64_encode, в заголовке Content-MD5.
    • priority: массив со списком доступных способов отправки запроса (транспортов), определяющий также порядок их применения до обнаружения первого доступного на сервере; приоритет доступных транспортов по умолчанию:
      • 'curl' (расширение curl)
      • 'fopen' (функция file_get_contents())
      • 'socket' (функция fsockopen())
    • timeout: таймаут в секундах, в течение которого разрешено продолжать выполнение запроса
    • verify: путь к файлу сертификата для подтверждения достоверности запроса (для транспортов 'curl' и 'fopen')
    • ssl: массив параметров для подключения через 'curl' с использованием SSL-сертификата:
      • 'key' — значение для параметра CURLOPT_SSLKEY
      • 'cert' — значение для параметра CURLOPT_SSLCERT
      • 'password' — значение для параметра CURLOPT_SSLCERTPASSWD
    • proxy_host: хост прокси-сервера для отправки запросов с использованием транспортов 'curl' или 'fopen'
    • proxy_port: порт прокси-сервера
    • proxy_user: имя пользователя для авторизации на прокси
    • proxy_password: пароль для авторизации на прокси
    • log: путь к альтернативному файлу для сохранения логов в директории wa-log/; по умолчанию логи сохраняются в файл waNet.error.log
  • $custom_headers

    Ассоциативный массив дополнительных заголовков для выполнения запроса к удаленному ресурсу.

Пример

$options = array(
    'format'        => waNet::FORMAT_JSON
    'timeout'       => 10,
    'authorization' => true,
    'login'         => $login,
    'password'      => $password,
);
$net = new waNet($options);

public function cookies ($path)

Устанавливает путь по умолчанию к файлу, содержащему cookies, для использования в качестве параметра CURLOPT_COOKIEFILE при подключении через curl. Это значение по умолчанию используется, только если в параметрах подключения через curl не указан иной путь к файлу cookies.

Параметры

  • $path

    Путь к файлу cookies.

Пример

$net = new waNet($options);
$net->cookies($path);

public function getResponse ($raw = false)

Возвращает содержимое последнего полученного ответа на запрос.

Параметры

  • $raw

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

Пример

$options['format'] = waNet::FORMAT_JSON;
$net = new waNet($options);
$decoded_response = $net->query($url);
$raw_response = $net->getResponse(true);

public function getResponseHeader ($header = null)

Возвращает содержимое заголовков последнего полученного ответа.

Параметры

  • $header

    Имя заголовка, содержимое которого нужно получить. Если не указано, метод вернет содержимое всех полученных заголовков.

Пример

$net = new waNet($options);
$response = $net->query($url);
$response_headers = $net->getResponseHeader();

public function query ($url, $content = [], $method = self::METHOD_GET, $callback = null)

Выполняет запрос к указанному ресурсу и возвращает раскодированное содержимое ответа в соответствии с указанным форматом.

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

Параметры

  • $url

    URL отправки запроса

  • $content

    Содержимое запроса

  • $method

    Метод отправки запроса:

    • waNet::METHOD_GET — GET
    • waNet::METHOD_POST — POST (для транспортов 'curl' и 'fopen')
    • waNet::METHOD_PUT — PUT (для транспортов 'curl' и 'fopen')
    • waNet::METHOD_PATCH — PATCH (для транспортов 'curl' и 'fopen')
    • waNet::METHOD_DELETE — DELETE (для транспорта 'curl')
  • $callback

    Значение типа callable, которое должно быть запущено после завершения выполнения запроса. Поддерживается только для отправки запросов с использованием транспорта curl.

Пример

$net = new waNet($options);
$response = $net->query($url, $content, waNet::METHOD_POST, ['myClass', 'some_callback_method']);

public function multiQuery ($namespace = null, $options = [])

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

С другими транспортами отправки запросов, кроме curl, метод не работает.

Порядок использования метода:

  1. Вызвать метод с произвольным непустым значением параметра $namespace — для инициализации данных.
  2. Вызвать несколько раз метод query() со значением параметра $callback типа callable.
  3. Ещё раз вызвать метод multiQuery() с тем же значением параметра $namespace. В результате этого вызова будут одновременно запущены все запросы через curl, инициированные в шаге 2, для которых при вызове метода query() для параметра $callback был указано значение типа callable. Если значение $callback указано не было, то запросы выполняются не параллельно, а последовательно — сразу же при вызове метода query() в предыдущем шаге 2, не дожидаясь данного шага 3.

Параметры

  • $namespace

    Произвольное текстовое обозначение для группы curl-запросов, которые нужно выполнить параллельно. Если при втором вызове метода multiQuery() значение этого параметра не указано, то по умолчанию будет использовано значение, которое было указано при первом вызове метода.

  • $options

    Массив параметров выполнения запросов через curl, которые должны применяться вместо значений, указанных в параметре $options при создании экземпляра класса, который используется для многократного вызова метода query() перед вторым вызовом метода multiQuery(). Значение параметра $options нужно указывать при первом вызове multiQuery().

Пример

waNet::multiQuery(
    'my_query',
    [
        'timeout' => 10,
    ]
);

$net = new waNet([
    'priority' => [
        'curl',
    ],
    // это значение не сработает, потому что оно переопределено при первом вызове multiQuery()
    'timeout' => 20,
]);

// эти запросы выполнятся одновременно — при втором вызове метода multiQuery()
// после их завершения будут по очереди выполнены обработчики, указанные в 4-м параметре при вызове метода query()
$response1 = $net->query($url1, $content1, waNet::METHOD_POST, ['myClass', 'some_callback_method']);
$response2 = $net->query($url2, $content2, waNet::METHOD_POST, ['myClass', 'another_callback_method']);
$response3 = $net->query($url3, $content3, waNet::METHOD_POST, ['myClass', 'extra_callback_method']);

// эти запросы выполнятся сразу же — не дожидаясь второго вызова multiQuery()
// потому что в 4-м параметре $callback не указан обработчик
$response4 = $net->query($url4, $content4, waNet::METHOD_POST);
$response5 = $net->query($url5, $content5, waNet::METHOD_POST);

waNet::multiQuery('my_query');

public function userAgent ($user_agent = null)

Устанавливает либо возвращает значение, которое будет использовано для заголовка «User-Agent«.

Параметры

  • $user_agent

    Новое значение, которое нужно установить для заголовка «User-Agent«. Если не указано, то метод только вернет текущее значение. По умолчанию используется значение вида "Webasyst-Framework/[номер версии Webasyst]".

Пример

$net = new waNet($options);
$net->userAgent($custom_user_agent);
$response = $net->query($url);

This class is useful for convenient sending of network requests using curl extension, and via file_get_contents and fsockopen functions. The class automatically uses the first of the sending methods (transports) available on the server, verifies the received response, and returns its contents, unpacked to the required format, if necessary.

How to use waNet class:

  1. Create a class instance by passing an array of initializing parameters to the constructor.
  2. If necessary, call «preparation» methods: cookies and userAgent.
  3. To actually send a request, call method query, which will return the response contents.
  4. If necessary, additionally call other methods returning more information about the received response: getResponse and getResponseHeader.

Methods

  • cookies

    Sets the default path to a cookies file.

  • getResponse

    Returns the contents of the last received response.

  • getResponseHeader

    Returns the contents of the last received response headers.

  • query

    Sends a request to specified URI.

  • multiQuery

    Runs several curl requests in parallel with subsequent execution of callback functions.

  • userAgent

    Sets a new or returns the current value of the «User-Agent» header.

public function __construct ($options)

Parameters

  • $options

    Array of parameters used for connecting to a remote resource. Accepted array keys:

    • format: format of the expected response: waNet::FORMAT_JSON (JSON), waNet::FORMAT_XML (XML), or waNet::FORMAT_RAW (simple response contents requiring no additional formatting)
    • charset: the charset used in the request to be sent; defaults to 'utf-8'
    • authorization: flag requiring authorization using Authorization header
    • login: user name for authorization
    • password: password for authorization
    • md5: flag requiring to specify the request contents, encoded with PHP functions md5 and base64_encode, in the Content-MD5 header
    • priority: array of explicitly specified request sending methods (transports) and their detection order, which must be used, in the specified order, to select the first transport available on the server only from the specified list; if not specified, the following transport list and their priority is used by default:
      • 'curl' (curl extension)
      • 'fopen' (file_get_contents() function)
      • 'socket' (fsockopen() function)
    • timeout: timeout in seconds during which it is allowed to continue the sending of a request
    • verify: path to a certificate file for request authentication (supported by transports 'curl' and 'fopen')
    • ssl:array of parameters used for connections via 'curl' using an SSL certificate:
      • 'key': value for parameter CURLOPT_SSLKEY
      • 'cert': value for parameter CURLOPT_SSLCERT
      • 'password': value for parameter CURLOPT_SSLCERTPASSWD
    • proxy_host: proxy host for sending requests via 'curl' or 'fopen' transports
    • proxy_port: proxy port
    • proxy_user: user name for proxy authorization
    • proxy_password: password for proxy authorization
    • log: alternative path error log file in wa-log/ directory; default path is waNet.error.log
  • $custom_headers

    Associative array of custom headers to be used for sending a request to a remote resource.

Example

$options = array(
    'format'        => waNet::FORMAT_JSON
    'timeout'       => 10,
    'authorization' => true,
    'login'         => $login,
    'password'      => $password,
);
$net = new waNet($options);

public function cookies ($path)

Sets the path to a file with cookies values for using as the CURLOPT_COOKIEFILE parameter value when connecting via curl. This default value is used, only if no other path to a cookies file is explicitly specified in curl connection parameters.

Parameters

  • $path

    Path to a cookies file.

Example

$net = new waNet($options);
$net->cookies($path);

public function getResponse ($raw = false)

Returns the contents of the last received response.

Parameters

  • $raw

    Flag requiring to return either raw (original) or formatted response contents. By default, formatted response contents are returned. The format used for response formatting must be the same as the value of the 'format' parameter passed to the class constructor.

Example

$options['format'] = waNet::FORMAT_JSON;
$net = new waNet($options);
$decoded_response = $net->query($url);
$raw_response = $net->getResponse(true);

public function getResponseHeader ($header = null)

Returns the contents of the last received response headers.

Parameters

  • $header

    name of header whose contents must be returned. If not specified, all received headers’ contents are returned.

Example

$net = new waNet($options);
$response = $net->query($url);
$response_headers = $net->getResponseHeader();

public function query ($url, $content = [], $method = self::METHOD_GET, $callback = null)

Sends a request to a remote resource and returns response contents formatted according to the specified format name.

Execution of this method may cause an exception; therefore, it must be used inside a try...catch block for correct error handling. Error codes in this case correspond to common HTTP server response codes.

Parameters

  • $url

    Request URL

  • $content

    Request contents

  • $method

    Sending method:

    • waNet::METHOD_GET: GET
    • waNet::METHOD_POST: POST (for transports 'curl' and 'fopen')
    • waNet::METHOD_PUT: PUT (for transports 'curl' and 'fopen')
    • waNet::METHOD_PATCH: PATCH (for transports 'curl' and 'fopen')
    • waNet::METHOD_DELETE: DELETE (for 'curl' transport)
  • $callback

    Value of the callable type, which must be called upon the request completion. Supported only for requests sent by the curl transport.

Example

$net = new waNet($options);
$response = $net->query($url, $content, waNet::METHOD_POST);

public function multiQuery ($namespace = null, $options = [])

Runs several curl requests in parallel with subsequent execution of callback functions. This allows your product to save the time required to make several simultaneous requests.

This method does not work with other transports except for curl.

How to use this method:

  1. Call the method with an arbitrary non-empty value of the $namespace parameter. This is required for data initialization.
  2. Make several calls of the query() method with a callable type value passed to the $callback parameter.
  3. Once again call the multiQuery() method with the same value of the $namespace parameter. This will simultaneously run all curl requests initialized in step 2, which have a callable type value passed as the $callback parameter for the query() method. If no correct value was passed as the $callback parameter then curl requests are performed sequentially rather than in parallel — immediately upon each call of the query() in the previous step 2, without waiting for this step 3.

Parameters

  • $namespace

    An arbitrary text name for a group of curl requests that must be run in parallel. If no value is specified during the second call of the multiQuery() method then the value passed during its first call is used by default.

  • $options

    Array of parameters used for curl requests which must be applied instead of those specified in the $options parameter when a class instance is created for multiple calls of the query() method before the second call of multiQuery(). A value of the $options parameter, if necessary, must be passed during the first call of this method.

Example

waNet::multiQuery(
    'my_query',
    [
        'timeout' => 10,
    ]
);

$net = new waNet([
    'priority' => [
        'curl',
    ],
    // this value will not be used because it is has been overridden during the 1st call of multiQuery()
    'timeout' => 20,
]);

// these requests will be executed simultaneously, during the 2nd call of multiQuery()
// upon their completion, callback functions passed as the 4th parameter for query() method calls will be executed
$response1 = $net->query($url1, $content1, waNet::METHOD_POST, ['myClass', 'some_callback_method']);
$response2 = $net->query($url2, $content2, waNet::METHOD_POST, ['myClass', 'another_callback_method']);
$response3 = $net->query($url3, $content3, waNet::METHOD_POST, ['myClass', 'extra_callback_method']);

// these requests will be executed sequentially at once, without waiting for the 2nd call of multiQuery()
// because no callbacks are passed for the 4th $callback parameter
$response4 = $net->query($url4, $content4, waNet::METHOD_POST);
$response5 = $net->query($url5, $content5, waNet::METHOD_POST);

waNet::multiQuery('my_query');

public function userAgent ($user_agent = null)

Sets a new or returns the current value of the «User-Agent» header.

Parameters

  • $user_agent

    New value to be set for «User-Agent» header. If not specified, method returns current header value. If not explicitly changed, default header value is "Webasyst-Framework/[Webasyst version]".

Example

$net = new waNet($options);
$net->userAgent($custom_user_agent);
$response = $net->query($url);
<?php /* * This file is part of Webasyst framework. * * Licensed under the terms of the GNU Lesser General Public License (LGPL). * http://www.webasyst.com/framework/license/ * * @link http://www.webasyst.com/ * @author Webasyst LLC * @copyright 2017 Webasyst LLC * @package wa-system * @subpackage files */ /** * Class waNet * @todo header handler * @todo error handler * @todo body handler * * @todo waBrowser class (with cookie support) */ class waNet { const TRANSPORT_CURL = ‘curl’; const TRANSPORT_FOPEN = ‘fopen’; const TRANSPORT_SOCKET = ‘socket’; /** * @see https://tools.ietf.org/html/rfc2616#section-5.1.1 */ const METHOD_GET = ‘GET’; const METHOD_POST = ‘POST’; const METHOD_PUT = ‘PUT’; const METHOD_PATCH = ‘PATCH’; // since 2.7.0 const METHOD_DELETE = ‘DELETE’; const FORMAT_JSON = ‘json’; const FORMAT_XML = ‘xml’; const FORMAT_RAW = ‘raw’; const FORMAT_CUSTOM = ‘custom’; protected $user_agent = ‘Webasyst Framework’; protected $accept_cookies = false; protected $cookies = null; protected $request_headers = array(); protected $options = array( ‘timeout’ => 15, ‘format’ => null, ‘request_format’ => null, ‘required_get_fields’ => array(), ‘charset’ => ‘utf-8’, ‘verify’ => true, ‘md5’ => false, ‘log’ => false, # authorization settings ‘authorization’ => false, ‘auth_type’ => ‘Basic’, ‘auth_key’ => null, ‘login’ => null, ‘password’ => null, # proxy settings ‘proxy_host’ => null, ‘proxy_port’ => null, ‘proxy_user’ => null, ‘proxy_password’ => null, ‘proxy_type’ => null, ‘proxy_auth’ => ‘basic’, # specify custom interface ‘interface’ => null, # string with list of expected codes separated comma or space; null to accept any code ‘expected_http_code’ => 200, ‘priority’ => array( ‘curl’, ‘fopen’, ‘socket’, ), ‘ssl’ => array( ‘key’ => », ‘cert’ => », ‘password’ => », ), ); private static $master_options = array(); protected $raw_response; protected $decoded_response; protected $response_header = array(); private $ch; private static $mh; /** @var waNet[] */ private static $instances = array(); /** * waNet constructor. * @param array $options key => value format * — $options[‘format’] — expected format of response * — $options[‘request_format’] — format of request data * … * @param array $custom_headers key => value format * @throws waException */ public function __construct($options = array(), $custom_headers = array()) { $this->user_agent = sprintf(‘Webasyst-Framework/%s’, wa()->getVersion(‘webasyst’)); if (strtoupper(substr(PHP_OS, 0, 3)) === ‘WIN’) { $this->options[‘verify’] = false; } $this->options = array_merge( $this->options, $this->getDefaultOptions(), $options, self::$master_options ); $this->request_headers = array_merge($this->request_headers, $custom_headers); } private function getDefaultOptions() { $config = wa()->getConfigPath().‘/net.php’; $options = array(); if (file_exists($config)) { $options = include($config); } if (!is_array($options)) { $options = array(); } return $options; } /** * @param string $user_agent * @return string */ public function userAgent($user_agent = null) { $current_user_agent = $this->user_agent; if ($user_agent != null) { $this->user_agent = $user_agent; } return $current_user_agent; } public function cookies($path) { $this->accept_cookies = true; $this->cookies = $path; } public function sendFile($url, $path) { } /** * @param $url * @param array|string|SimpleXMLElement|DOMDocument $content Parameter type relate to request format (xml/json/etc) * @param string $method * @param callable $callback * @return string|array|SimpleXMLElement|waNet Type related to response for response format (json/xml/etc). Self return for promises * @throws waException */ public function query($url, $content = array(), $method = self::METHOD_GET, $callback = null) { $transport = $this->getTransport($url); $this->buildRequest($url, $content, $method); $this->startQuery(); switch ($transport) { case self::TRANSPORT_CURL: $response = $this->runCurl($url, $content, $method, array(), $callback); break; case self::TRANSPORT_FOPEN: $response = $this->runStreamContext($url, $content, $method); break; case self::TRANSPORT_SOCKET: $response = $this->runSocketContext($url, $content, $method); break; default: throw new waNetException(_ws(‘No supported network transports are available.’), 500); break; } if ($response instanceof self) { return $response; } else { $this->onQueryComplete($response); return $this->getResponse(); } } protected function onQueryComplete($response) { $this->decodeResponse($response); if ($this->options[‘expected_http_code’] !== null) { $expected = $this->options[‘expected_http_code’]; if (!is_array($expected)) { $expected = preg_split(‘@[,:;.s]+@’, $this->options[‘expected_http_code’]); } if (empty($this->response_header[‘http_code’]) || !in_array($this->response_header[‘http_code’], $expected)) { throw new waNetException($response, $this->response_header[‘http_code’]); } } } /** * @param string $url * @param array|string|SimpleXMLElement|DOMDocument $content * @param string $method */ protected function buildRequest(&$url, &$content, &$method) { if ($content && in_array($method, [self::METHOD_GET, self::METHOD_DELETE])) { // // Unable to encode FORMAT_XML and FORMAT_JSON for METHOD_GET. // Have to deal with it here. // $format = ifempty($this->options[‘request_format’], $this->options[‘format’]); if (in_array($format, array(self::FORMAT_XML), true)) { // FORMAT_XML, METHOD_GET becomes FORMAT_XML, METHOD_POST if ($method === self::METHOD_GET) { $method = self::METHOD_POST; } } else { // FORMAT_JSON, METHOD_GET or METHOD_DELETE becomes FORMAT_RAW, METHOD_GET (METHOD_DELETE) $get = is_string($content) ? $content : http_build_query($content); $url .= strpos($url, ‘?’) ? ‘&’ : ‘?’.$get; $content = array(); } } // When URL is too long, move some fields to POST body $post = self::getPost($url, $this->options[‘required_get_fields’]); if ($post) { switch ($method) { // GET becomes POST // PUT and POST are ok as is // DELETE don’t know what to do case self::METHOD_GET: $method = self::METHOD_POST; break; case self::METHOD_DELETE: throw new waNetException(‘Too long URL for METHOD_DELETE’); } $content = array_merge($post, $content); } switch ($method) { case self::METHOD_POST: case self::METHOD_PUT: case self::METHOD_PATCH: case self::METHOD_DELETE: $content = $this->encodeRequest($content); break; } } protected function buildHeaders($transport, $raw = true) { $this->request_headers[‘Connection’] = ‘close’; $this->request_headers[‘Date’] = date(‘c’); if (empty($this->request_headers[‘Accept’])) { switch ($this->options[‘format’]) { case self::FORMAT_JSON: $this->request_headersAccept«] = «application/json«; break; case self::FORMAT_XML: $this->request_headersAccept«] = «text/xml«; break; default: $this->request_headers[‘Accept’] = ‘*/*’; break; } } $this->request_headers[‘Accept-Charset’] = $this->options[‘charset’]; /** * Accept * | Accept-Charset ; Section 14.2 * | Accept-Encoding ; Section 14.3 * | Accept-Language ; Section 14.4 * | Authorization ; Section 14.8 * | Expect ; Section 14.20 * | From ; Section 14.22 * | Host ; Section 14.23 * | If-Match ; Section 14.24 */ if (!empty($this->options[‘authorization’])) { if (empty($this->options[‘auth_key’])) { $authorization = base64_encode(sprintf(«%s:%s«, $this->options[‘login’], $this->options[‘password’])); } else { $authorization = $this->options[‘auth_key’]; } $this->request_headersAuthorization«] = $this->options[‘auth_type’] . « » . $authorization; } $this->request_headers[‘User-Agent’] = $this->user_agent; $this->request_headers[‘X-Framework-Method’] = $transport; if ($raw) { return $this->request_headers; } else { $headers = array(); foreach ($this->request_headers as $header => $value) { $headers[] = sprintf(‘%s: %s’, $header, $value); } return $headers; } } /** * @param array|string|SimpleXMLElement|DOMDocument $content * @return string * @throws waException */ protected function encodeRequest($content) { $format = ifempty($this->options[‘request_format’], $this->options[‘format’]); if (!is_string($content)) { switch ($format) { case self::FORMAT_JSON: $content = json_encode($content); break; case self::FORMAT_XML: if (is_object($content)) { $class = get_class($content); if (class_exists(‘SimpleXMLElement’) && ($content instanceof SimpleXMLElement)) { /** * @var SimpleXMLElement $content */ $content = (string)$content->asXML(); } elseif (class_exists(‘DOMDocument’) && ($content instanceof DOMDocument)) { /** * @var DOMDocument $content */ if (!empty($this->options[‘charset’])) { $content->encoding = $this->options[‘charset’]; } $content->preserveWhiteSpace = false; $content = (string)$content->saveXML(); } else { $message = ‘Unsupported class «%s» of content object. Expected instance of SimpleXMLElement or DOMDocument classes.’; throw new waNetException(sprintf($message, $class)); } } else { throw new waNetException(‘XML content must be an instance of SimpleXMLElement or DOMDocument classes.’); } break; default: $content = http_build_query($content); break; } } $this->request_headers[‘Content-Length’] = strlen($content); if (empty($this->request_headers[‘Content-Type’])) { switch ($format) { case self::FORMAT_JSON: $this->request_headers[‘Content-Type’] = ‘application/json’; break; case self::FORMAT_XML: $this->request_headers[‘Content-Type’] = ‘application/xml’; break; case self::FORMAT_CUSTOM: //$this->request_headers[‘Content-Type’] =’application/’.$this->options[‘custom_content_type’]; break; default: $this->request_headers[‘Content-Type’] = ‘application/x-www-form-urlencoded’; break; } } if (!empty($this->options[‘md5’])) { $this->request_headers[‘Content-MD5’] = base64_encode(md5($content, true)); } return $content; } /** * @param string $response * @throws waException */ protected function decodeResponse($response) { $this->raw_response = $response; $this->decoded_response = null; switch ($this->options[‘format’]) { case self::FORMAT_JSON: $this->decoded_response = waUtils::jsonDecode($this->raw_response, true); break; case self::FORMAT_XML: $xml_options = LIBXML_NOCDATA | LIBXML_NOENT | LIBXML_NONET; libxml_use_internal_errors(true); if (PHP_VERSION_ID < 80000) { libxml_disable_entity_loader(false); } libxml_clear_errors(); $this->decoded_response = @simplexml_load_string($this->raw_response, null, $xml_options); if ($this->decoded_response === false) { if ($error = libxml_get_last_error()) { /** * @var LibXMLError $error */ $this->log($error->message); throw new waNetException(‘Error while decode XML response: ‘.$error->message, $error->code); } } break; default: $this->decoded_response = $this->raw_response; break; } } /** * @param bool $raw If param is true method returns raw response string * @return string|array|SimpleXMLElement Type related to response for response format (json/xml/etc) */ public function getResponse($raw = false) { return $raw ? $this->raw_response : $this->decoded_response; } /** * @param string|null $header * @return array|mixed|null */ public function getResponseHeader($header = null) { if (!empty($header)) { if (array_key_exists($header, $this->response_header)) { return $this->response_header[$header]; } $header_alias = $header = str_replace(‘-‘, ‘_’, $header); foreach ($this->response_header as $field => $value) { // Ignore register of headers according to RFC if (strcasecmp($field, $header) === 0 || strcasecmp($header_alias, $header) === 0) { return $value; } } return null; } return $this->response_header; } protected function parseHeader($http_response_header) { foreach ($http_response_header as $header) { $t = explode(‘:’, $header, 2); if (isset($t[1])) { $this->response_header[trim($t[0])] = trim($t[1]); } elseif (strlen($header)) { $this->response_header[] = $header; if (preg_match(‘#HTTP/[0-9.]+s+([0-9]+)#’, $header, $out)) { $this->response_header[‘http_code’] = intval($out[1]); } } } } /** * @param string $url * @return string|bool */ protected function getTransport($url) { $available = array(); $scheme = parse_url($url, PHP_URL_SCHEME); if (extension_loaded(‘curl’) && function_exists(‘curl_init’)) { $available[self::TRANSPORT_CURL] = true; } else { $hint[] = »; } if (@ini_get(‘allow_url_fopen’)) { if (in_array($scheme, stream_get_wrappers(), true)) { $available[self::TRANSPORT_FOPEN] = true; } else { $hint[] = »; } } elseif (empty($available)) { $hint[] = »; } if (function_exists(‘fsockopen’)) { if (in_array(‘tcp’, stream_get_transports(), true)) { $available[self::TRANSPORT_SOCKET] = true; } else { $hint[] = »; } } elseif (empty($available)) { $hint[] = ‘Enable fsockopen’; } if (!empty($this->options[‘proxy_host’]) && $available[self::TRANSPORT_CURL]) { return self::TRANSPORT_CURL; } foreach ($this->options[‘priority’] as $transport) { if (!empty($available[$transport])) { return $transport; } } return false; } protected function runCurl($url, $params, $method, $curl_options = array(), $callback = null) { $this->getCurl($url, $params, $method, $curl_options); if (!empty($callback) && is_callable($callback) && !empty(self::$namespace) && !empty(self::$mh[self::$namespace])) { return $this->addMultiCurl($callback); } else { $response = @curl_exec($this->ch); return $this->handleCurlResponse($response); } } private function handleCurlResponse($response) { if (empty($response)) { $error_no = curl_errno($this->ch); $error_str = curl_error($this->ch); if ($error_no == 28) { throw new waNetTimeoutException(sprintf(‘Curl error %d: %s’, $error_no, $error_str), $error_no); } else { throw new waNetException(sprintf(‘Curl error %d: %s’, $error_no, $error_str), $error_no); } } else { $header_size = curl_getinfo($this->ch, CURLINFO_HEADER_SIZE); $this->parseHeader(preg_split(‘@[rn]+@’, substr($response, 0, $header_size))); $body = substr($response, $header_size); } return $body; } protected function onMultiQueryComplete($callback) { $content = curl_multi_getcontent($this->ch); try { $body = $this->handleCurlResponse($content); curl_multi_remove_handle(self::$mh[self::$namespace], $this->ch); $this->onQueryComplete($body); $response = $this->getResponse(); call_user_func_array($callback, array($this, $response)); } catch (waException $ex) { call_user_func_array($callback, array($this, $ex)); } } private static $namespace = null; private function addMultiCurl($callback) { $id = curl_multi_add_handle(self::$mh[self::$namespace], $this->ch); self::$instances[self::$namespace][$id] = array( ‘instance’ => $this, ‘callback’ => $callback, ); return $this; } public static function multiQuery($namespace = null, $options = array()) { if ($options) { self::$master_options = $options; } if ($namespace && !isset(self::$mh[$namespace])) { if (empty(self::$mh[$namespace]) && function_exists(‘curl_multi_init’)) { self::$mh[$namespace] = curl_multi_init(); if (!isset(self::$instances[$namespace])) { self::$instances[$namespace] = array(); } self::$namespace = $namespace; } } elseif ((($namespace === null) || (self::$namespace === $namespace)) && isset(self::$mh[self::$namespace])) { $namespace = self::$namespace; if (self::$instances[$namespace]) { $active = null; do { $mrc = curl_multi_exec(self::$mh[$namespace], $active); } while ($mrc == CURLM_CALL_MULTI_PERFORM); while ($active && $mrc == CURLM_OK) { if (curl_multi_select(self::$mh[$namespace]) == —1) { usleep(100); } do { $mrc = curl_multi_exec(self::$mh[$namespace], $active); } while ($mrc == CURLM_CALL_MULTI_PERFORM); } foreach (self::$instances[$namespace] as $id => $data) { $instance = $data[‘instance’]; /** @var waNet $instance */ $instance->onMultiQueryComplete($data[‘callback’]); } self::$instances = array(); } unset(self::$instances[$namespace]); curl_multi_close(self::$mh[$namespace]); unset(self::$mh[$namespace]); } self::$master_options = []; } private function getCurl($url, $content, $method, $curl_options = array()) { if (extension_loaded(‘curl’) && function_exists(‘curl_init’)) { if (empty($this->ch)) { if (!($this->ch = curl_init())) { throw new waNetException(_ws(«Error cUrl init«)); } if (curl_errno($this->ch) != 0) { throw new waNetException(_ws(«Error cUrl init«).‘ ‘.curl_errno($this->ch).‘ ‘.curl_error($this->ch)); } if (!is_array($curl_options)) { $curl_options = array(); } $curl_default_options = array( CURLOPT_HEADER => 1, CURLOPT_RETURNTRANSFER => 1, CURLOPT_TIMEOUT => $this->options[‘timeout’], CURLOPT_CONNECTTIMEOUT => $this->options[‘timeout’], CURLOPT_DNS_CACHE_TIMEOUT => 3600, CURLOPT_USERAGENT => $this->user_agent, ); if (isset($this->options[‘interface’])) { $curl_default_options[CURLOPT_INTERFACE] = $this->options[‘interface’]; } if ($this->options[‘verify’]) { $curl_default_options[CURLOPT_SSL_VERIFYHOST] = 2; $curl_default_options[CURLOPT_SSL_VERIFYPEER] = true; if (is_string($this->options[‘verify’])) { if (!file_exists($this->options[‘verify’])) { throw new InvalidArgumentException( «SSL CA bundle not found: {$this->options[‘verify’]}» ); } $curl_default_options[CURLOPT_CAINFO] = $this->options[‘verify’]; } } else { $curl_default_options[CURLOPT_SSL_VERIFYHOST] = 0; $curl_default_options[CURLOPT_SSL_VERIFYPEER] = false; } if (array_filter($this->options[‘ssl’], ‘strlen’)) { if (!empty($this->options[‘ssl’][‘key’])) { $curl_default_options[CURLOPT_SSLKEY] = $this->options[‘ssl’][‘key’]; } if (!empty($this->options[‘ssl’][‘cert’])) { $curl_default_options[CURLOPT_SSLCERT] = $this->options[‘ssl’][‘cert’]; } if (!empty($this->options[‘ssl’][‘password’])) { $curl_default_options[CURLOPT_SSLCERTPASSWD] = $this->options[‘ssl’][‘password’]; } } if ($this->accept_cookies) { $curl_default_options[CURLOPT_COOKIEFILE] = $this->cookies; } foreach ($curl_default_options as $option => $value) { if (!isset($curl_options[$option])) { $curl_options[$option] = $value; } } if (isset($this->options[‘proxy_host’]) && strlen($this->options[‘proxy_host’])) { $curl_options[CURLOPT_HTTPPROXYTUNNEL] = true; $curl_options[CURLOPT_PROXYTYPE] = (empty($this->options[‘proxy_type’]) ? CURLPROXY_HTTP : $this->options[‘proxy_type’]); if (isset($this->options[‘proxy_port’]) && $this->options[‘proxy_port’]) { $curl_options[CURLOPT_PROXY] = sprintf(«%s:%s«, $this->options[‘proxy_host’], $this->options[‘proxy_port’]); } else { $curl_options[CURLOPT_PROXY] = $this->options[‘proxy_host’]; } if (isset($this->options[‘proxy_user’]) && strlen($this->options[‘proxy_user’])) { $curl_options[CURLOPT_PROXYUSERPWD] = sprintf(«%s:%s«, $this->options[‘proxy_user’], $this->options[‘proxy_password’]); } } foreach ($curl_options as $param => $option) { curl_setopt($this->ch, $param, $option); } } $curl_options = array(); switch ($method) { case self::METHOD_POST: $curl_options[CURLOPT_POST] = 1; if ($content) { $curl_options[CURLOPT_POSTFIELDS] = $content; } break; case self::METHOD_DELETE: case self::METHOD_PATCH: case self::METHOD_PUT: $curl_options[CURLOPT_CUSTOMREQUEST] = $method; if ($content) { $curl_options[CURLOPT_POST] = 0; $curl_options[CURLOPT_POSTFIELDS] = $content; } break; default: if ($content) { $curl_options[CURLOPT_POST] = 0; $curl_options[CURLOPT_CUSTOMREQUEST] = null; $curl_options[CURLOPT_POSTFIELDS] = null; } } $headers = $this->buildHeaders(‘curl’, false); if ($headers) { $curl_options[CURLOPT_HTTPHEADER] = $headers; } if (empty($curl_options[CURLOPT_POST]) && empty($curl_options[CURLOPT_POSTFIELDS])) { if (!ini_get(‘safe_mode’) && !ini_get(‘open_basedir’)) { // This is a useful option to have, but it is disabled in paranoid environments // (which emits a warning). Also, does not apply to POST requests. $curl_options[CURLOPT_FOLLOWLOCATION] = true; } } $curl_options[CURLOPT_URL] = $url; foreach ($curl_options as $param => $option) { curl_setopt($this->ch, $param, $option); } } } private function startQuery() { wa()->getStorage()->close(); } protected function runStreamContext($url, $content, $method) { $context = $this->getStreamContext($content, $method); $response = @file_get_contents($url, false, $context); $response_code = ‘unknown’; $hint = »; if (!empty($http_response_header)) { /** * @link http://php.net/manual/en/reserved.variables.httpresponseheader.php * @var string[] $http_response_header */ $this->parseHeader($http_response_header); foreach ($http_response_header as $header) { /* HTTP/1.1 404 Not Found*/ if (preg_match(‘@^HTTP/d(.d)?s+(d{3})s+(.+)$@i’, $header, $matches)) { $response_code = (int)$matches[2]; $hint = « Hint: {$matches[3]}»; } elseif (preg_match(‘@^status:s+(d+)s+(.+)$@i’, $header, $matches)) { $response_code = (int)$matches[1]; $hint = « Hint: {$matches[2]}»; break; } } } if ($this->options[‘expected_http_code’] !== null) { if (!$response || !in_array($response_code, array(‘unknown’, $this->options[‘expected_http_code’]), true)) { if (empty($hint)) { $hint = $this->getHint(__LINE__); } throw new waNetException(«Invalid server response with code {$response_code} while request {$url}.{$hint}nt(fopen used)«); } } return $response; } /** * @param $content * @param $method * @return resource */ private function getStreamContext($content, $method) { $context_params = array( ‘ignore_errors’ => true,//PHP >= 5.2.10 ‘timeout’ => $this->options[‘timeout’], ‘user_agent’ => $this->user_agent, ); $headers = $this->buildHeaders(‘fopen’, false); if (isset($this->options[‘proxy_host’]) && strlen($this->options[‘proxy_host’])) { $proxy = $this->options[‘proxy_host’]; if (isset($this->options[‘proxy_port’]) && intval($this->options[‘proxy_port’])) { $proxy .= ‘:’.intval($this->options[‘proxy_port’]); } $context_params[‘proxy’] = $proxy; if (!empty($this->options[‘proxy_user’])) { $auth = base64_encode(sprintf(‘%s:%s’, $this->options[‘proxy_user’], $this->options[‘proxy_password’])); $headers[] = «Proxy-Authorization: Basic $auth«; } } $context_params[‘header’] = implode(«rn», $headers); //5.2.10 array support if (in_array($method, array(self::METHOD_POST, self::METHOD_PUT, self::METHOD_PATCH))) { $context_params += array( ‘method’ => $method, ‘content’ => $content, ); } $context_params += array( ‘follow_location’ => true,//PHP >= 5.3.4 ‘max_redirects’ => 5, ); $context_params = [‘http’ => $context_params]; //SSL if (!empty($this->options[‘verify’])) { $context_params[‘ssl’][‘verify_peer’] = true; $context_params[‘ssl’][‘verify_peer_name’] = true; $context_params[‘ssl’][‘allow_self_signed’] = false; if (is_string($this->options[‘verify’])) { if (!file_exists($this->options[‘verify’])) { throw new RuntimeExceptionSSL CA bundle not found: {$this->options[‘verify’]}»); } $context_params[‘ssl’][‘cafile’] = $this->options[‘verify’]; } else { // PHP 5.6 or greater will find the system cert by default. When // < 5.6, try load it if (PHP_VERSION_ID < 50600) { //TODO try default system path with ca files //$context_params[‘ssl’][‘cafile’] = »; } } } else { $context_params[‘ssl’][‘verify_peer’] = false; $context_params[‘ssl’][‘verify_peer_name’] = false; } return stream_context_create($context_params); } /** * @param $url * @param $content * @param $method * @return bool|string * @throws waException */ protected function runSocketContext($url, $content, $method) { $host = parse_url($url, PHP_URL_HOST); $port = parse_url($url, PHP_URL_PORT); if (empty($port)) { if (true) { $port = 80; } else { $port = 81; } } $headers = array( «Host» => $host.(($port == 80) ? » : ‘:’.$port), ); $headers = array_merge($headers, $this->buildHeaders(‘socket’)); $error_no = null; $error_str = null; $response_code = ‘unknown’; $body = null; $socket = @fsockopen($host, $port, $error_no, $error_str, $this->options[‘timeout’]); $response = »; if ($socket) { $path = parse_url($url, PHP_URL_PATH); $request = parse_url($url, PHP_URL_QUERY); if (strlen($request)) { $path .= ‘?’.$request; } $out = «{$method} {$path} HTTP/1.1rn»; foreach ($headers as $header => $value) { $out .= sprintf(«%s: %srn», $header, $value); } $out .= «rn»; $out .= $content; fwrite($socket, $out); while (!feof($socket)) { $response .= fgets($socket, 1024); } fclose($socket); } if (!$response) { if ($error_no) { $hint = «Socket error: #{$error_no} {$error_str}»; } else { $hint = $this->getHint(__LINE__); } $this->log($hint); throw new waNetException(«Invalid server response with code {$response_code} while request {$url}.{$hint}nt(fsockopen used)«); } else { list($header, $body) = explode(«rnrn», $response, 2); $this->parseHeader(preg_split(‘@[rn]+@’, $header)); } return $body; } /** * 413 Entity Too Large error workaround * @see http://stackoverflow.com/questions/686217/maximum-on-http-header-values * @param string $url * @param string[] $required_get_fields * @return array POST data */ private static function getPost(&$url, $required_get_fields = array()) { $post = array(); /** * Apache 2.0/2.2 8K * @see http://httpd.apache.org/docs/2.2/mod/core.html#limitrequestfieldsize * * nginx 4K-8K * @see http://nginx.org/en/docs/http/ngx_http_core_module.html#large_client_header_buffers * * IIS 4K-8K */ if (strlen($url) > 2096) { parse_str(parse_url($url, PHP_URL_QUERY), $post); $url = preg_replace(‘@?.+$@’, », $url); $get = array(); foreach ($required_get_fields as $field) { if (isset($post[$field])) { $get[$field] = $post[$field]; unset($post[$field]); } unset($value); } if ($get) { $url .= ‘?’.http_build_query($get); } } return $post; } private function getHint($line) { $hint = »; if (($error = error_get_last()) && (abs($line$error[‘line’]) < 30) && ($error[‘file’] == __FILE__) ) { $hint = strip_tags($error[‘message’]); } return $hint; } private function log($message) { waLog::log($message, ifempty($this->options[‘log’], ‘waNet.error.log’)); } public function __destruct() { if (!empty($this->ch)) { curl_close($this->ch); } } /** * @since PHP 5.6.0 * @return array */ public function __debugInfo() { return array( ‘options’ => $this->options, ‘request_headers’ => $this->request_headers, ‘response_headers’ => $this->response_header, ‘raw’ => $this->raw_response, ‘preview’ => $this->decoded_response, ); } public function getResponseDebugInfo() { return [ ‘headers’ => $this->response_header, ‘body’ => $this->raw_response, ]; } }

(PHP 4, PHP 5, PHP 7, PHP 8)

error_logОтправляет сообщение об ошибке заданному обработчику ошибок

Описание

error_log(
    string $message,
    int $message_type = 0,
    ?string $destination = null,
    ?string $additional_headers = null
): bool

Список параметров

message

Сообщение об ошибке, которое должно быть логировано.

message_type

Определяет куда отправлять ошибку.
Возможны следующие значения:

Типы журналов error_log()

0 Сообщение message отправляется в системный регистратор PHP, используя
механизм логирования операционной системы, или файл, в зависимости от значения директивы
error_log
в конфигурационном файле. Это значение по умолчанию.
1 Сообщение message отправляется электронной почтой на адрес, установленный в параметре
destination. Это единственный тип сообщения, где используется четвёртый параметр
additional_headers.
2 Больше не используется.
3 message применяется к указанному в
destination файлу. Перенос строки автоматически не добавляется в конец
message.
4 Сообщение message отправляется напрямую в обработчик
логера SAPI.
destination

Назначение. Устанавливается в зависимости от параметра
message_type.

additional_headers

Дополнительные заголовки. Используется, когда значение параметра message_type
1.
Данный тип сообщения использует ту же внутреннюю функцию, что и
mail().

Возвращаемые значения

Возвращает true в случае успешного выполнения или false в случае возникновения ошибки.
Если message_type равен нулю, функция всегда возвращает true,
независимо от того, может ли ошибка логироваться или нет.

Список изменений

Версия Описание
8.0.0 Параметр destination и
additional_headers теперь допускают значение null.

Примеры

Пример #1 Примеры использования error_log()


<?php
// Отправляет уведомление посредством серверного лога, если мы не можем
// подключиться к базе данных.
if (!Ora_Logon($username, $password)) {
error_log("База данных Oracle недоступна!", 0);
}
// Уведомить администратора по электронной почте, если невозможно выделить ресурсы для FOO
if (!($foo = allocate_new_foo())) {
error_log("Большая проблема, мы выпали из FOO!", 1,
"operator@example.com");
}
// другой способ вызвать error_log():
error_log("Вы ошиблись!", 3, "/var/tmp/my-errors.log");
?>

Примечания

Внимание

error_log() не является бинарно-безопасной функцией. message обрезается по null-символу.

Подсказка

message не должен содержать null-символ. Учтите, что message может передаваться в файл, по почте, в syslog и т.д. Используйте подходящую преобразующую или экранирующую функцию, base64_encode(), rawurlencode() или addslashes() перед вызовом error_log().

kevindougans at gmail dot com

12 years ago


Advice to novices: This function works great along with "tail" which is a unix command to watch a log file live. There are versions of Tail for Windows too, like Tail for Win32 or Kiwi Log Viewer.

Using both error_log() and tail to view the php_error.log you can debug code without having to worry so much about printing debug messages to the screen and who they might be seen by.

Further Note: This works even better when you have two monitors setup. One for your browser and IDE and the other for viewing the log files update live as you go.


Sion

4 years ago


DO NOT try to output TOO LARGE texts in the error_log();

if you try to output massive amounts of texts it will either cut of the text at about 8ooo characters (for reasonable massive strings, < 32 K characters) or (for insanely massive strings, about 1.6 million characters) totally crash without even throwing an error or anything (I even put it in a try/catch without getting any result from the catch).

I had this problem when I tried to debug a response from a wp_remote_get(); all of my error_log() worked as they should, except for ONE of them... (-_-)
After about a day of debugging I finally found out why & that's why I type this.

Apparently the response contained a body with over 1.6 million chars (or bytes? (whatever strlen() returns)).

If you have a string of unknown length, use this:
$start_index = 0;
$end_index = 8000;
error_log( substr( $output_text , $start_index , $end_index ) );


frank at booksku dot com

16 years ago


Beware!  If multiple scripts share the same log file, but run as different users, whichever script logs an error first owns the file, and calls to error_log() run as a different user will fail *silently*!

Nothing more frustrating than trying to figure out why all your error_log calls aren't actually writing, than to find it was due to a *silent* permission denied error!


i dot buttinoni at intandtel dot com

14 years ago


Be carefull. Unexpected PHP dies when 2GByte of file log reached (on systems having upper file size limit).
A work aorund is rotate logs :)

php at kennel17 dot NOSPAM dot co dot uk

17 years ago


It appears that the system log = stderr if you are running PHP from the command line, and that often stderr = stdout.  This means that if you are using a custom error to both display the error and log it to syslog, then a command-line user will see the same error reported twice.

Anonymous

19 years ago


when using error_log to send email, not all elements of an extra_headers string are handled the same way.  "From: " and "Reply-To: " header values will replace the default header values. "Subject: " header values won't: they are *added* to the mail header but don't replace the default, leading to mail messages with two Subject fields.

<?php

error_log

("sometext", 1, "zigzag@my.domain",
 
"Subject: FoonFrom: Rizzlas@my.domainn");?>

---------------%<-----------------------
To: zigzag@my.domain
Envelope-to: zigzag@my.domain
Date: Fri, 28 Mar 2003 13:29:02 -0500
From: Rizzlas@my.domain
Subject: PHP error_log message
Subject: Foo
Delivery-date: Fri, 28 Mar 2003 13:29:03 -0500

sometext
---------------%<---------------------

quoth the docs: "This message type uses the same internal function as mail() does." 

mail() will also fail to set a Subject field based on extra_header data - instead it takes a seperate argument to specify a "Subject: " string.

php v.4.2.3, SunOS 5.8


russ at russtanner dot com

3 years ago


You can easily filter messages sent to error_log() using "tail" and "grep" on *nix systems. This makes monitoring debug messages easy to see during development.

Be sure to "tag" your error message with a unique string so you can filter it using "grep":

In your code:

error_log("DevSys1 - FirstName: $FirstName - LastName: $Lastname");

On your command line:

tail -f /var/log/httpd/error_log | grep DevSys1

In this example, we pipe apache log output to grep (STDIN) which filters it for you only showing messages that contain "DevSys1".

The "-f" option means "follow" which streams all new log entries to your terminal or to any piped command that follows, in this case "grep".


Matthew Swift

3 years ago


Relative paths are accepted as the destination of message_type 3, but beware that the root directory is determined by the context of the call to error_log(), which can change, so that one instance of error_log () in your code can lead to the creation of multiple log files in different locations.

In a WordPress context, the root directory will be the site's root in many cases, but it will be /wp-admin/ for AJAX calls, and a plugin's directory in other cases. If you want all your output to go to one file, use an absolute path.


paul dot chubb at abs dot gov dot au

14 years ago


When logging to apache on windows, both error_log and also trigger_error result in an apache status of error on the front of the message. This is bad if all you want to do is log information. However you can simply log to stderr however you will have to do all message assembly:

LogToApache($Message) {
        $stderr = fopen('php://stderr', 'w');
        fwrite($stderr,$Message);
        fclose($stderr);
}


SJL

15 years ago


"It appears that the system log = stderr if you are running PHP from the command line"

Actually, it seems that PHP logs to stderr if it can't write to the log file. Command line PHP falls back to stderr because the log file is (usually) only writable by the webserver.


stepheneliotdewey at GmailDotCom

15 years ago


Note that since typical email is unencrypted, sending data about your errors over email using this function could be considered a security risk. How much of a risk it is depends on how much and what type of information you are sending, but the mere act of sending an email when something happens (even if it cannot be read) could itself imply to a sophisticated hacker observing your site over time that they have managed to cause an error.

Of course, security through obscurity is the weakest kind of security, as most open source supporters will agree. This is just something that you should keep in mind.

And of course, whatever you do, make sure that such emails don't contain sensitive user data.


p dot lhonorey at nospam-laposte dot net

16 years ago


Hi !

Another trick to post "HTML" mail body. Just add "Content-Type: text/html; charset=ISO-8859-1" into extra_header string. Of course you can set charset according to your country or Env or content.

EG: Error_log("<html><h2>stuff</h2></html>",1,"eat@joe.com","subject  :lunchnContent-Type: text/html; charset=ISO-8859-1");

Enjoy !


eguvenc at gmail dot com

14 years ago


<?php

//Multiline error log class

// ersin güvenç 2008 eguvenc@gmail.com

//For break use "n" instead 'n'
Class log {

 
//

 
const USER_ERROR_DIR = '/home/site/error_log/Site_User_errors.log';

  const
GENERAL_ERROR_DIR = '/home/site/error_log/Site_General_errors.log';
/*

   User Errors...

  */

   
public function user($msg,$username)

    {

   
$date = date('d.m.Y h:i:s');

   
$log = $msg."   |  Date:  ".$date."  |  User:  ".$username."n";

   
error_log($log, 3, self::USER_ERROR_DIR);

    }

   
/*

   General Errors...

  */

   
public function general($msg)

    {

   
$date = date('d.m.Y h:i:s');

   
$log = $msg."   |  Date:  ".$date."n";

   
error_log($msg."   |  Tarih:  ".$date, 3, self::GENERAL_ERROR_DIR);

    }

}

$log = new log();

$log->user($msg,$username); //use for user errors

//$log->general($msg); //use for general errors

?>

franz at fholzinger dot com

17 years ago


In the case of missing your entries in the error_log file:
When you use error_log in a script that does not produce any output, which means that you cannot see anything during the execution of the script, and when you wonder why there are no error_log entries produced in your error_log file, the reasons can be:
- you did not configure error_log output in php.ini
- the script has a syntax error and did therefore not execute

daniel dot fukuda at gmail dot com

13 years ago


If you have a problem with log file permission *silently*
it's best to leave error_log directive unset so errors will be written in your Apache log file for current VirtualHost.

Anonymous

2 years ago


Depending on the error, you may also want to add an error 500 header, and a message for the user:

$message =  'Description of the error.';
error_log($message);
header($_SERVER['SERVER_PROTOCOL'] . ' 500 Internal Server Error', true, 500);
exit($message);


Robert Chapin

4 years ago


When error_log() unexpectedly uses stdout, you should check if the php.ini value for error_log is empty in your CLI environment.  Something as simple as this might restore expected behavior:

<?php ini_set('error_log', 'error_log'); ?>


kazezb at nospam dot carleton dot edu

17 years ago


It appears that error_log() only logs the first line of multi-line log messages. To log a multi-line message, either log each line individually or write the message to another file.

Anonymous

13 years ago


After scouring the internet for getting event logging to
work in syslog on Windows 2003, I found the following
from this post and was able to successfully get Windows
Event Viewer to log PHP errors/notices:

http://forums.iis.net/p/1159662/1912015.aspx#1913338

   1. Copy the PHP 5 binaries to "C:php".
   2. Right-click My Computer and select Properties to bring
up the Computer Properties dialog. Switch to the Advanced
tab and click Environment Variables. Find the system
environment variable PATH, edit it and add ";C:php"
(without the quotes) to the end.
   3. Make sure that the configuration file "php.ini" resides
in the directory "C:php" and contains the correct path
settings.
   4. DELETE any old "php.ini" files from "C:WINDOWS"
and other directories.
   5. Open REGEDIT, navigate to the key
"HKLMSOFTWAREPHP" and DELETE the string value
"IniFilePath" from there. It is outdated and no longer
necessary!
   6. Modify NTFS security permissions of the directory
"C:php" to give Read and Execute permissions to (1) the
IIS Guest Account and (2) the group IIS_WPG.
   7. Modify NTFS security permissions of the directories
"C:phpsession" and "C:phpupload" to give additional
Modify permissions to (1) the IIS Guest Account and (2)
the group IIS_WPG.
   8. Navigate to the registry key
"HKLMSYSTEMCurrentControlSetServicesEventlog
Application" and edit the value "CustomSD" there. Find
the substring "(D;;0xf0007;;;BG)" which Denies access to
the application event log for Builtin Guest accounts (like
the IIS Web User account) and replace this substring with
"(A;;0x3;;;BG)" which allows read and write access. Please
pay attention to leave the rest of the security string intact.
Damaging this value can have dangerous effects!
   9. Create or update the registry key
"HKLMSYSTEMCurrentControlSetServicesEventlogApplication
PHP-5.2.0" (adapt the last to your version part
if necessary) with the following values:

          * "EventMessageFile" (REG_EXPAND_SZ) = "C:phpphp5ts.dll"

          * "TypesSupported" (REG_DWORD) = 7


Понравилась статья? Поделить с друзьями:
  • W211 ошибка 9092
  • Wan ошибка аутентификации тип pppoe
  • W210 как скинуть ошибки
  • Wan ошибка аутентификации неверное имя пользователя или пароль
  • W203 ошибка epc