/**
  * This send function sends a special command to the REST server with additional parameter.
  *
  * @author David Pauli <*****@*****.**>
  * @param String command The path which is requested in the REST client.
  * @param String[] $postParameter Add specific parameters to the REST server.
  * @since 0.0.0
  * @since 0.0.1 Use HTTPRequestMethod enum.
  * @since 0.1.0 Allow empty message body if the status code is 204.
  * @since 0.1.2 Restructure the logging message and fix the PATCH call.
  * @since 0.1.2 Add error reporting.
  * @since 0.1.3 Remove isRESTCommand function.
  * @since 0.2.1 Refactor the complete send method.
  */
 public static function send($command = "", $postParameter = array())
 {
     self::errorReset();
     if (!InputValidator::isArray($postParameter)) {
         Logger::warning("ep6\\RESTClient\\Post parameter (" . $postParameter . ") are not valid.");
         self::errorSet("RESTC-5");
         return null;
     }
     if (!self::$ISCONNECTED) {
         Logger::warning("ep6\\RESTClient\nClient is not connected.");
         self::errorSet("RESTC-6");
         return null;
     }
     $protocol = self::$ISSSL ? "https" : "http";
     $url = $protocol . "://" . self::$HOST . "/" . self::PATHTOREST . "/" . self::$SHOP . "/" . $command;
     $headers = array("Accept: " . self::HTTP_ACCEPT, "Content-Type: " . self::HTTP_CONTENT_TYPE_JSON, "User-Agent: " . self::USER_AGENT);
     // add authentification if there is a token
     if (InputValidator::isAuthToken(self::$AUTHTOKEN)) {
         array_push($headers, "Authorization: Bearer " . self::$AUTHTOKEN);
     }
     # parse cookies
     if (!InputValidator::isEmptyArray(self::$COOKIES)) {
         $cookiesValues = array();
         foreach (self::$COOKIES as $key => $value) {
             array_push($cookiesValues, $key . "=" . $value);
         }
         array_push($headers, "Cookie: " . implode("; ", $cookiesValues));
     }
     $curl = curl_init($url);
     curl_setopt($curl, CURLOPT_FAILONERROR, 1);
     // show full errors
     curl_setopt($curl, CURLOPT_FORBID_REUSE, 0);
     // connection can be opened
     curl_setopt($curl, CURLOPT_FRESH_CONNECT, 0);
     // no new connection required
     curl_setopt($curl, CURLOPT_NOBODY, 0);
     // show body
     curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
     // get response as string
     curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 0);
     // no connection timeout
     curl_setopt($curl, CURLOPT_CONNECTTIMEOUT_MS, 0);
     // no connection timeout
     curl_setopt($curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_NONE);
     // cURL will choose the http version
     curl_setopt($curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER);
     // understand ipv4 and ipv6
     curl_setopt($curl, CURLINFO_HEADER_OUT, 1);
     // save the header in the log
     curl_setopt($curl, CURLOPT_HEADER, 1);
     // get the header
     if (self::$ISSSL) {
         curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);
         // don't check the peer ssl cerrificate
         curl_setopt($curl, CURLOPT_PROTOCOLS, CURLPROTO_HTTPS);
         curl_setopt($curl, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTPS);
         curl_setopt($curl, CURLOPT_SSLVERSION, 0);
         // default ssl version
     } else {
         curl_setopt($curl, CURLOPT_PROTOCOLS, CURLPROTO_HTTP);
         curl_setopt($curl, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP);
     }
     switch (self::$HTTP_REQUEST_METHOD) {
         case HTTPRequestMethod::GET:
             curl_setopt($curl, CURLOPT_HTTPGET, 1);
             break;
         case HTTPRequestMethod::POST:
             $JSONpostfield = JSONHandler::createJSON($postParameter);
             curl_setopt($curl, CURLOPT_POST, 1);
             curl_setopt($curl, CURLOPT_POSTREDIR, 0);
             // don't post on redirects
             curl_setopt($curl, CURLOPT_POSTFIELDS, $JSONpostfield);
             break;
         case HTTPRequestMethod::PUT:
             $JSONpostfield = JSONHandler::createJSON($postParameter);
             array_push($headers, "Content-Length: " . strlen($JSONpostfield));
             curl_setopt($curl, CURLOPT_POSTFIELDS, $JSONpostfield);
             curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'PUT');
             break;
         case HTTPRequestMethod::DELETE:
             $JSONpostfield = JSONHandler::createJSON($postParameter);
             curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "DELETE");
             curl_setopt($curl, CURLOPT_POSTFIELDS, $JSONpostfield);
             break;
         case HTTPRequestMethod::PATCH:
             $JSONpostfield = "[" . JSONHandler::createJSON($postParameter) . "]";
             curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "PATCH");
             curl_setopt($curl, CURLOPT_POSTFIELDS, $JSONpostfield);
             break;
     }
     curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
     $response = curl_exec($curl);
     $info = curl_getinfo($curl);
     $error = curl_error($curl);
     curl_close($curl);
     # get header and body
     list($header, $body) = self::explodeResponse($response);
     $header = trim($header);
     $content = trim($body);
     $logMessage = "Request:\n" . "Parameters: " . http_build_query($postParameter) . "\n" . $info["request_header"] . "Response:\n" . "Size (Header/Request): " . $info["header_size"] . "/" . $info["request_size"] . " Bytes\n" . "Time (Total/Namelookup/Connect/Pretransfer/Starttransfer/Redirect): " . $info["total_time"] . " / " . $info["namelookup_time"] . " / " . $info["connect_time"] . " / " . $info["pretransfer_time"] . " / " . $info["starttransfer_time"] . " / " . $info["redirect_time"] . " seconds\n" . $response . "\n";
     Logger::notify("ep6\\RESTClient:\n" . $logMessage);
     # parse header, response code and body
     self::explodeHeader($header);
     self::$HTTP_RESPONSE_CODE = (int) $info["http_code"];
     if (!InputValidator::isEmpty($content)) {
         self::$CONTENT = $content;
     }
 }
 /**
  * This send function sends a special command to the REST server with additional parameter.
  *
  * @author David Pauli <*****@*****.**>
  * @since 0.0.0
  * @since 0.0.1 Use HTTPRequestMethod enum.
  * @since 0.1.0 Allow empty message body if the status code is 204.
  * @api
  * @param String command The path which is requested in the REST client.
  * @param String[] postfields Add specific parameters to the REST server.
  * @return mixed[] The returned elements as array.
  */
 public static function send($command, $postfields = array())
 {
     if (!InputValidator::isRESTCommand($command) || !self::$ISCONNECTED || !InputValidator::isArray($postfields)) {
         return null;
     }
     $protocol = self::$ISSSL ? "https" : "http";
     $url = $protocol . "://" . self::$HOST . "/" . self::PATHTOREST . "/" . self::$SHOP . "/" . $command;
     $headers = array("Accept: " . self::HTTP_ACCEPT, "Content-Type: " . self::HTTP_CONTENT_TYPE);
     if (InputValidator::isAuthToken(self::$AUTHTOKEN)) {
         array_push($headers, "Authorization: Bearer " . self::$AUTHTOKEN);
     }
     $curl = curl_init($url);
     curl_setopt($curl, CURLOPT_FAILONERROR, 1);
     // show full errors
     curl_setopt($curl, CURLOPT_FORBID_REUSE, 0);
     // connection can be opened
     curl_setopt($curl, CURLOPT_FRESH_CONNECT, 0);
     // no new connection required
     curl_setopt($curl, CURLOPT_NOBODY, 0);
     // show body
     curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
     // get response as string
     curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 0);
     // no connection timeout
     curl_setopt($curl, CURLOPT_CONNECTTIMEOUT_MS, 0);
     // no connection timeout
     curl_setopt($curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_NONE);
     // cURL will choose the http version
     curl_setopt($curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER);
     // understand ipv4 and ipv6
     if (self::$ISSSL) {
         curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);
         // don't check the peer ssl cerrificate
         curl_setopt($curl, CURLOPT_PROTOCOLS, CURLPROTO_HTTPS);
         curl_setopt($curl, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTPS);
         curl_setopt($curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_DEFAULT);
         // default ssl version
     } else {
         curl_setopt($curl, CURLOPT_PROTOCOLS, CURLPROTO_HTTP);
         curl_setopt($curl, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP);
     }
     switch (self::$HTTP_REQUEST_METHOD) {
         case HTTPRequestMethod::GET:
             curl_setopt($curl, CURLOPT_HTTPGET, 1);
             break;
         case HTTPRequestMethod::POST:
             $JSONpostfield = JSONHandler::createJSON($postfields);
             curl_setopt($curl, CURLOPT_POST, 1);
             curl_setopt($curl, CURLOPT_POSTREDIR, 0);
             // don't post on redirects
             curl_setopt($curl, CURLOPT_POSTFIELDS, $JSONpostfield);
             break;
         case HTTPRequestMethod::PUT:
             $JSONpostfield = JSONHandler::createJSON($postfields);
             array_push($headers, "Content-Length: " . strlen($JSONpostfield));
             curl_setopt($curl, CURLOPT_POSTFIELDS, $JSONpostfield);
             curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'PUT');
             break;
         case HTTPRequestMethod::DELETE:
             $JSONpostfield = JSONHandler::createJSON($postfields);
             curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "DELETE");
             curl_setopt($curl, CURLOPT_POSTFIELDS, $JSONpostfield);
             break;
         case HTTPRequestMethod::PATCH:
             $JSONpostfield = JSONHandler::createJSON($postfields);
             curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "PATCH");
             curl_setopt($curl, CURLOPT_POSTFIELDS, $JSONpostfield);
             break;
     }
     curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
     $response = curl_exec($curl);
     $info = curl_getinfo($curl);
     $error = curl_error($curl);
     curl_close($curl);
     $logMessage = self::$HTTP_REQUEST_METHOD . " " . $info["url"] . "<br/>" . "<strong>Response</strong>: " . $info["http_code"] . ": <pre>" . htmlspecialchars($response) . "</pre><br/>" . "<strong>Content-Type</strong>: " . $info["content_type"] . "<br/>" . "<strong>Size</strong> (Header/Request): " . $info["header_size"] . "/" . $info["request_size"] . " Bytes<br/>" . "<strong>Time</strong> (Total/Namelookup/Connect/Pretransfer/Starttransfer/Redirect): " . $info["total_time"] . " / " . $info["namelookup_time"] . " / " . $info["connect_time"] . " / " . $info["pretransfer_time"] . " / " . $info["starttransfer_time"] . " / " . $info["redirect_time"] . " seconds<br/>";
     Logger::notify("<strong>HTTP-SEND</strong>:<br/>" . $logMessage);
     // if message body is empty this is allowed with 204
     if (!$response && $info["http_code"] != "204") {
         Logger::error("Error with send REST client: " . $error);
         return null;
     } elseif (!in_array($info["http_code"], array("200", "201", "204"))) {
         Logger::warning("Get wrong response: " . $info["http_code"]);
         return null;
     }
     return JSONHandler::parseJSON($response);
 }