// Extract host name
$host = str_replace('http://', '', $url);
- if (isInString('/', $host)) $host = substr($host, 0, strpos($host, '/'));
+ if (isInString('/', $host)) {
+ $host = substr($host, 0, strpos($host, '/'));
+ } // END - if
// Generate relative URL
//* DEBUG: */ debugOutput('SCRIPT=' . $script);
}
//* DEBUG: */ debugOutput('SCRIPT=' . $script);
- if (substr($script, 0, 1) == '/') $script = substr($script, 1);
+ if (substr($script, 0, 1) == '/') {
+ $script = substr($script, 1);
+ } // END - if
// Return host name
return $host;
}
// Send a GET request
-function sendGetRequest ($script, $data = array()) {
- // Extract host name from script
+function sendGetRequest ($script, $data = array(), $removeHeader = false) {
+ // Extract hostname and port from script
$host = extractHostnameFromUrl($script);
// Add data
$body = http_build_query($data, '', '&');
// There should be data, else we don't need to extend $script with $body
- if (empty($body)) {
+ if (!empty($body)) {
// Do we have a question-mark in the script?
if (strpos($script, '?') === false) {
// No, so first char must be question mark
$script .= $body;
// Remove trailed & to make it more conform
- if (substr($script, -1, 1) == '&') $script = substr($script, 0, -1);
+ if (substr($script, -1, 1) == '&') {
+ $script = substr($script, 0, -1);
+ } // END - if
} // END - if
// Generate GET request header
// Send the raw request
$response = sendRawRequest($host, $request);
+ // Should we remove header lines?
+ if ($removeHeader === true) {
+ // Okay, remove them
+ $response = removeHttpHeaderFromResponse($response);
+ } // END - if
+
// Return the result to the caller function
return $response;
}
// Send a POST request
-function sendPostRequest ($script, $postData) {
- // Is postData an array?
- if (!is_array($postData)) {
- // Abort here
- logDebugMessage(__FUNCTION__, __LINE__, sprintf("postData is not an array. Type: %s", gettype($postData)));
- return array('', '', '');
- } // END - if
-
+function sendPostRequest ($script, array $postData, $removeHeader = false) {
// Extract host name from script
$host = extractHostnameFromUrl($script);
// Send the raw request
$response = sendRawRequest($host, $request);
+ // Should we remove header lines?
+ if ($removeHeader === true) {
+ // Okay, remove them
+ $response = removeHttpHeaderFromResponse($response);
+ } // END - if
+
// Return the result to the caller function
return $response;
}
// Sends a raw request to another host
function sendRawRequest ($host, $request) {
// Init errno and errdesc with 'all fine' values
- $errno = '0'; $errdesc = '';
+ $errno = '0';
+ $errdesc = '';
+
+ // Default port is 80
+ $port = 80;
// Initialize array
$response = array('', '', '');
// Load include
loadIncludeOnce('inc/classes/resolver.class.php');
+ // Extract port part from host
+ $portArray = explode(':', $host);
+ if (count($portArray) == 2) {
+ // Extract host and port
+ $host = $portArray[0];
+ $port = $portArray[1];
+ } elseif (count($portArray) > 2) {
+ // This should not happen!
+ debug_report_bug(__FUNCTION__, __LINE__, 'Invalid ' . $host . '. Please report this to the Mailer-Project team.');
+ }
+
// Get resolver instance
$resolver = new HostnameResolver();
$ip = $resolver->resolveHostname($host);
// Connect to host directly
- $fp = fsockopen($ip, 80, $errno, $errdesc, 30);
+ $fp = fsockopen($ip, $port, $errno, $errdesc, 30);
}
// Is there a link?
// Do we use proxy?
if ($useProxy === true) {
// Setup proxy tunnel
- $response = setupProxyTunnel($host, $fp);
+ $response = setupProxyTunnel($host, $port, $fp);
// If the response is invalid, abort
if ((count($response) == 3) && (empty($response[0])) && (empty($response[1])) && (empty($response[2]))) {
} // END - if
// Add it to response
- $response[] = trim($line);
+ $response[] = $line;
} // END - while
// Close socket
// Not found / access forbidden
logDebugMessage(__FUNCTION__, __LINE__, 'Unexpected status code ' . $response[0] . ' detected. "200 OK" was expected.');
$response = array('', '', '');
+ } else {
+ // Check array for chuncked encoding
+ $response = unchunkHttpResponse($response);
} // END - if
// Return response
}
// Sets up a proxy tunnel for given hostname and through resource
-function setupProxyTunnel ($host, $resource) {
+function setupProxyTunnel ($host, $port, $resource) {
// Initialize array
$response = array('', '', '');
// Generate CONNECT request header
- $proxyTunnel = 'CONNECT ' . $host . ':80 HTTP/1.0' . getConfig('HTTP_EOL');
+ $proxyTunnel = 'CONNECT ' . $host . ':' . $port . ' HTTP/1.0' . getConfig('HTTP_EOL');
$proxyTunnel .= 'Host: ' . $host . getConfig('HTTP_EOL');
// Use login data to proxy? (username at least!)
return $respArray;
}
+// Check array for chuncked encoding
+function unchunkHttpResponse (array $response) {
+ // Default is not chunked
+ $isChunked = false;
+
+ // Check if we have chunks
+ foreach ($response as $line) {
+ // Make lower-case and trim it
+ $line = trim(strtolower($line));
+
+ // Entry found?
+ if ((strpos($line, 'transfer-encoding') !== false) && (strpos($line, 'chunked') !== false)) {
+ // Found!
+ $isChunked = true;
+ break;
+ } // END - if
+ } // END - foreach
+
+ // Is it chunked?
+ if ($isChunked === true) {
+ // Good, we still have the HTTP headers in there, so we need to get rid
+ // of them temporarly
+ //* DEBUG: */ die('<pre>'.htmlentities(print_r(removeHttpHeaderFromResponse($response), true)).'</pre>');
+ $tempResponse = http_chunked_decode(implode('', removeHttpHeaderFromResponse($response)));
+
+ // We got a string back from http_chunked_decode(), so we need to convert it back to an array
+ //* DEBUG: */ die('tempResponse['.strlen($tempResponse).']=<pre>'.replaceReturnNewLine(htmlentities($tempResponse)).'</pre>');
+
+ // Re-add the headers
+ $response = merge_array($GLOBALS['http_headers'], stringToArray("\n", $tempResponse));
+ } // END - if
+
+ // Return the unchunked array
+ return $response;
+}
+
+// Removes HTTP header lines from a response array (e.g. output from send<Get|Post>Request() )
+function removeHttpHeaderFromResponse (array $response) {
+ // Save headers for later usage
+ $GLOBALS['http_headers'] = array();
+
+ // The first array element has to contain HTTP
+ if ((isset($response[0])) && (substr(strtoupper($response[0]), 0, 5) == 'HTTP/')) {
+ // Okay, we have headers, now remove them with a second array
+ $response2 = $response;
+ foreach ($response as $line) {
+ // Remove line
+ array_shift($response2);
+
+ // Add full line to temporary global array
+ $GLOBALS['http_headers'][] = $line;
+
+ // Trim it for testing
+ $lineTest = trim($line);
+
+ // Is this line empty?
+ if (empty($lineTest)) {
+ // Then stop here
+ break;
+ } // END - if
+ } // END - foreach
+
+ // Write back the array
+ $response = $response2;
+ } // END - if
+
+ // Return the modified response array
+ return $response;
+}
+
// Taken from www.php.net isInStringIgnoreCase() user comments
function isEmailValid ($email) {
// Check first part of email address
if (SQL_NUMROWS($result) == 1) {
// Load the entry
$content = SQL_FETCHARRAY($result);
- die('<pre>'.print_r($content, true).'</pre>');
+ die(__FUNCTION__.':<br />content=<pre>'.print_r($content, true).'</pre>');
} // END - if
// Free result
return $OUT;
}
+
+/**
+ * determine if a string can represent a number in hexadecimal
+ *
+ * @param $hex A string to check if it is hex-encoded
+ * @return $foo True if the string is a hex, otherwise false
+ * @author Marques Johansson
+ * @link http://php.net/manual/en/function.http-chunked-decode.php#89786
+ */
+function isHexadecimal ($hex) {
+ // Make it lowercase
+ $hex = strtolower(trim(ltrim($hex, '0')));
+
+ // Fix empty strings to zero
+ if (empty($hex)) {
+ $hex = 0;
+ } // END - if
+
+ // Simply compare decode->encode result with original
+ return ($hex == dechex(hexdec($hex)));
+}
+
+// Replace "\r" with "[r]" and "\n" with "[n]" and add a final new-line to make
+// them visible to the developer. Use this function to debug e.g. buggy HTTP
+// response handler functions.
+function replaceReturnNewLine ($str) {
+ return str_replace("\r", '[r]', str_replace("\n", '[n]
+', $str));
+}
+
+// Converts a given string by splitting it up with given delimiter similar to
+// explode(), but appending the delimiter again
+function stringToArray ($delimiter, $string) {
+ // Init array
+ $strArray = array();
+
+ // "Walk" through all entries
+ foreach (explode($delimiter, $string) as $split) {
+ // Append the delimiter and add it to the array
+ $strArray[] = $split . $delimiter;
+ } // END - foreach
+
+ // Return array
+ return $strArray;
+}
+
//-----------------------------------------------------------------------------
// Automatically re-created functions, all taken from user comments on www.php.net
//-----------------------------------------------------------------------------
-//
if (!function_exists('html_entity_decode')) {
// Taken from documentation on www.php.net
function html_entity_decode ($string) {
$k = urlencode($prefix . $k);
} // END - if
- if ((!empty($key)) || ($key === 0)) $k = $key . '[' . urlencode($k) . ']';
+ if ((!empty($key)) || ($key === 0)) {
+ $k = $key . '[' . urlencode($k) . ']';
+ } // END - if
if (is_array($v) || is_object($v)) {
array_push($ret, http_build_query($v, '', $sep, $k));
}
} // END - foreach
- if (empty($sep)) $sep = ini_get('arg_separator.output');
+ if (empty($sep)) {
+ $sep = ini_get('arg_separator.output');
+ } // END - if
return implode($sep, $ret);
}
} // END - if
+if (!function_exists('http_chunked_decode')) {
+ /**
+ * dechunk an http 'transfer-encoding: chunked' message.
+ *
+ * @param $chunk The encoded message
+ * @return $dechunk The decoded message. If $chunk wasn't encoded properly debug_report_bug() is being called
+ * @author Marques Johansson
+ * @link http://php.net/manual/en/function.http-chunked-decode.php#89786
+ */
+ function http_chunked_decode ($chunk) {
+ // Init some variables
+ $offset = 0;
+ $len = mb_strlen($chunk);
+ $dechunk = '';
+
+ // Walk through all chunks
+ while ($offset < $len) {
+ // Where does the \r\n begin?
+ $lineEndAt = mb_strpos($chunk, getConfig('HTTP_EOL'), $offset);
+
+ /* DEBUG: *
+ print 'lineEndAt[<em>'.__LINE__.'</em>]='.$lineEndAt.'<br />
+offset[<em>'.__LINE__.'</em>]='.$offset.'<br />
+len='.$len.'<br />
+next[offset]=<pre>'.replaceReturnNewLine(htmlentities(mb_substr($chunk, $offset, 10))).'</pre>';
+ /* DEBUG: */
+
+ // Get next hex-coded chunk length
+ $chunkLenHex = mb_substr($chunk, $offset, ($lineEndAt - $offset));
+
+ /* DEBUG: *
+ print 'chunkLenHex[<em>'.__LINE__.'</em>]='.replaceReturnNewLine(htmlentities($chunkLenHex)).'<br />
+';
+ /* DEBUG: */
+
+ // Validation if it is hexadecimal
+ if (!isHexadecimal($chunkLenHex)) {
+ // Please help debugging this
+ //* DEBUG: */ die('ABORT:chunkLenHex=<pre>'.replaceReturnNewLine(htmlentities($chunkLenHex)).'</pre>');
+ debug_report_bug(__FUNCTION__, __LINE__, 'Value ' . $chunkLenHex . ' is not properly chunk encoded.');
+
+ // This won't be reached
+ return $chunk;
+ } // END - if
+
+ // Position of next chunk is right after \r\n
+ $offset = $offset + strlen($chunkLenHex) + strlen(getConfig('HTTP_EOL'));
+ $chunkLen = hexdec(rtrim($chunkLenHex, getConfig('HTTP_EOL')));
+
+ /* DEBUG: *
+ print 'chunkLen='.$chunkLen.'<br />
+offset[<em>'.__LINE__.'</em>]='.$offset.'<br />';
+ /* DEBUG: */
+
+ // Moved out for debugging
+ $next = mb_substr($chunk, $offset, $chunkLen);
+ //* DEBUG: */ print 'next=<pre>'.replaceReturnNewLine(htmlentities($next)).'</pre>';
+
+ // Count occurrences of \r\n
+ $count = mb_substr_count($next, getConfig('HTTP_EOL'));
+
+ // Correct it because we need to subtract occurrences of \r\n
+ $chunkLen = hexdec(rtrim($chunkLenHex, getConfig('HTTP_EOL'))) - ($count * strlen(getConfig('HTTP_EOL')));
+
+ $dechunk .= mb_substr($chunk, $offset, $chunkLen);
+
+ /* DEBUG: *
+ print('offset[<em>'.__LINE__.'</em>]='.$offset.'<br />
+lineEndAt[<em>'.__LINE__.'</em>]='.$lineEndAt.'<br />
+len='.$len.'<br />
+count='.$count.'<br />
+chunkLen='.$chunkLen.'<br />
+chunkLenHex='.$chunkLenHex.'<br />
+dechunk=<pre>'.replaceReturnNewLine(htmlentities($dechunk)).'</pre>
+chunk=<pre>'.replaceReturnNewLine(htmlentities($chunk)).'</pre>');
+ /* DEBUG: */
+
+ // Is $offset + $chunkLen larger than or equal $len?
+ if (($offset + $chunkLen) >= $len) {
+ // Then stop processing here
+ break;
+ } // END - if
+
+ // Calculate next offset of chunk
+ $offset = mb_strpos($chunk, getConfig('HTTP_EOL'), $offset + $chunkLen) + 2;
+
+ /* DEBUG: *
+ print('offset[<em>'.__LINE__.'</em>]='.$offset.'<br />
+next[100]=<pre>'.replaceReturnNewLine(htmlentities(mb_substr($chunk, $offset, 100))).'</pre>
+---:---:---:---:---:---:---:---:---<br />
+');
+ /* DEBUG: */
+ } // END - while
+
+ // Return de-chunked string
+ return $dechunk;
+ }
+} // END - if
+
// [EOF]
?>