From 04d6e40981c7d295219902ede8d9e72e88eb7280 Mon Sep 17 00:00:00 2001 From: TJ Date: Fri, 21 Oct 2011 16:08:19 +0100 Subject: [PATCH 1/8] 4875: add HTTPRequest class that supports cookies and redirects without fopen() or curl --- include/classes/HTTPRequest.class.php | 125 ++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 include/classes/HTTPRequest.class.php diff --git a/include/classes/HTTPRequest.class.php b/include/classes/HTTPRequest.class.php new file mode 100644 index 00000000..68a38b07 --- /dev/null +++ b/include/classes/HTTPRequest.class.php @@ -0,0 +1,125 @@ + to support cookies +# usage: +# $r = new HTTPRequest('http://www.example.com', $cookie_array); +# echo $r->DownloadToString(); + +class HTTPRequest +{ + var $_fp; // HTTP socket + var $_url; // full URL + var $_host; // HTTP host + var $_protocol; // protocol (HTTP/HTTPS) + var $_uri; // request URI + var $_port; // port + var $_cookies = array(); // array of cookies + + // scan url + function _scan_url() + { + $req = $this->_url; + + $pos = strpos($req, '://'); + $this->_protocol = strtolower(substr($req, 0, $pos)); + + $req = substr($req, $pos+3); + $pos = strpos($req, '/'); + if($pos === false) + $pos = strlen($req); + $host = substr($req, 0, $pos); + + if(strpos($host, ':') !== false) + { + list($this->_host, $this->_port) = explode(':', $host); + } + else + { + $this->_host = $host; + $this->_port = ($this->_protocol == 'https') ? 443 : 80; + } + + $this->_uri = substr($req, $pos); + if($this->_uri == '') + $this->_uri = '/'; + } + + // constructor + function HTTPRequest($url, $cookies) + { + $this->_url = $url; + $this->_scan_url(); + $this->_cookies = $cookies; + trigger_error("HTTPRequest(\"" . $url . "\""); + foreach($cookies as $key => $value) { + trigger_error("Cookie: " . $key . "=" . $value ); + } + } + + // download URL to string + function DownloadToString() + { + $crlf = "\r\n"; + + // generate request + $req = 'GET ' . $this->_uri . ' HTTP/1.0' . $crlf + . 'Host: ' . $this->_host . $crlf; + + // add cookies if any exist + if(count($this->_cookies)) { + $req .= "Cookie: "; + foreach($this->_cookies as $key => $value) { + $req .= $key . "=" . $value . "; "; + } + $req .= $crlf; + } + $req .= $crlf; + + // fetch + $this->_fp = fsockopen(($this->_protocol == 'https' ? 'ssl://' : '') . $this->_host, $this->_port); + fwrite($this->_fp, $req); + $response = ''; + while(is_resource($this->_fp) && $this->_fp && !feof($this->_fp)) + $response .= fread($this->_fp, 1024); + fclose($this->_fp); + + // split header and body + $pos = strpos($response, $crlf . $crlf); + if($pos === false) + return($response); + $header = substr($response, 0, $pos); + $body = substr($response, $pos + 2 * strlen($crlf)); + + // parse headers + $headers = array(); + $lines = explode($crlf, $header); + foreach($lines as $line) { + if(($pos = strpos($line, ':')) !== false) { + $key = strtolower(trim(substr($line, 0, $pos))); + $value = trim(substr($line, $pos+1)); + $headers[$key] = $value; + if(strcmp($key, "set-cookie") == 0) { + if(($pos = strpos($value, '=')) !== false) { + $key = trim(substr($value, 0, $pos)); + $value = trim(substr($value, $pos+1)); + $this->_cookies[$key] = $value; + } + } + } + } + + // redirection? + if(isset($headers['location'])) + { + $http = new HTTPRequest($headers['location'], $this->_cookies); + return($http->DownloadToString()); + } + else + { + return($body); + } + } +} +?> + From 9b479ed5bd49c4d06f786de41f0b970b50e431ac Mon Sep 17 00:00:00 2001 From: TJ Date: Thu, 6 Oct 2011 12:29:37 +0100 Subject: [PATCH 2/8] 4875: Use HTTPRequest class for importing IMS Common Cartridges --- home/ims/ims_import.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/home/ims/ims_import.php b/home/ims/ims_import.php index 57ba69c0..a1cd1e30 100644 --- a/home/ims/ims_import.php +++ b/home/ims/ims_import.php @@ -70,6 +70,7 @@ require_once(TR_INCLUDE_PATH.'classes/DAO/TestsQuestionsAssocDAO.class.php'); require_once(TR_INCLUDE_PATH.'classes/DAO/ContentTestsAssocDAO.class.php'); require_once(TR_INCLUDE_PATH.'classes/FileUtility.class.php'); /* for clr_dir() and preImportCallBack and dirsize() */ +require_once(TR_INCLUDE_PATH.'classes/HTTPRequest.class.php'); /* for importing from remote servers that use Cookies and/or redirection */ require_once(TR_INCLUDE_PATH.'lib/pclzip.lib.php'); require_once(TR_INCLUDE_PATH.'lib/pclzip_callback.lib.php'); @@ -808,7 +809,8 @@ function glossaryCharacterData($parser, $data){ } if (isset($_REQUEST['url']) && ($_REQUEST['url'] != 'http://') ) { - if ($content = @file_get_contents($_REQUEST['url'])) { + $http_req = new HTTPRequest($_REQUEST['url'], array()); + if ($content = $http_req->DownloadToString()) { $filename = substr(time(), -6). '.zip'; $full_filename = TR_CONTENT_DIR . $filename; @@ -1445,4 +1447,4 @@ function glossaryCharacterData($parser, $data){ } exit; -?> \ No newline at end of file +?> From 2b4bf4709e9d5109f1a5bc604c81fe1f415ff551 Mon Sep 17 00:00:00 2001 From: TJ Date: Fri, 21 Oct 2011 16:09:49 +0100 Subject: [PATCH 3/8] 4875: remove HTTPRequest debug logging --- include/classes/HTTPRequest.class.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/include/classes/HTTPRequest.class.php b/include/classes/HTTPRequest.class.php index 68a38b07..45d3fb44 100644 --- a/include/classes/HTTPRequest.class.php +++ b/include/classes/HTTPRequest.class.php @@ -51,10 +51,6 @@ function HTTPRequest($url, $cookies) $this->_url = $url; $this->_scan_url(); $this->_cookies = $cookies; - trigger_error("HTTPRequest(\"" . $url . "\""); - foreach($cookies as $key => $value) { - trigger_error("Cookie: " . $key . "=" . $value ); - } } // download URL to string From aabf2b62315ae483448420f2a07c8cd2c597c650 Mon Sep 17 00:00:00 2001 From: TJ Date: Thu, 6 Oct 2011 17:42:29 +0100 Subject: [PATCH 4/8] 4875: HTTPRequest: add exception and error reporting --- include/classes/HTTPRequest.class.php | 86 ++++++++++++++++----------- 1 file changed, 50 insertions(+), 36 deletions(-) diff --git a/include/classes/HTTPRequest.class.php b/include/classes/HTTPRequest.class.php index 45d3fb44..d77e15ca 100644 --- a/include/classes/HTTPRequest.class.php +++ b/include/classes/HTTPRequest.class.php @@ -15,6 +15,8 @@ class HTTPRequest var $_uri; // request URI var $_port; // port var $_cookies = array(); // array of cookies + var $_errstr; + var $_errno; // scan url function _scan_url() @@ -73,47 +75,59 @@ function DownloadToString() $req .= $crlf; // fetch - $this->_fp = fsockopen(($this->_protocol == 'https' ? 'ssl://' : '') . $this->_host, $this->_port); - fwrite($this->_fp, $req); - $response = ''; - while(is_resource($this->_fp) && $this->_fp && !feof($this->_fp)) - $response .= fread($this->_fp, 1024); - fclose($this->_fp); + try { + $this->_fp = fsockopen(($this->_protocol == 'https' ? 'ssl://' : '') . $this->_host, + $this->_port, $this->_errorno, $this->_errstr); + if($this->_fp) { + fwrite($this->_fp, $req); + $response = ''; + while(is_resource($this->_fp) && $this->_fp && !feof($this->_fp)) + $response .= fread($this->_fp, 1024); + fclose($this->_fp); - // split header and body - $pos = strpos($response, $crlf . $crlf); - if($pos === false) - return($response); - $header = substr($response, 0, $pos); - $body = substr($response, $pos + 2 * strlen($crlf)); + // split header and body + $pos = strpos($response, $crlf . $crlf); + if($pos === false) + return($response); + $header = substr($response, 0, $pos); + $body = substr($response, $pos + 2 * strlen($crlf)); - // parse headers - $headers = array(); - $lines = explode($crlf, $header); - foreach($lines as $line) { - if(($pos = strpos($line, ':')) !== false) { - $key = strtolower(trim(substr($line, 0, $pos))); - $value = trim(substr($line, $pos+1)); - $headers[$key] = $value; - if(strcmp($key, "set-cookie") == 0) { - if(($pos = strpos($value, '=')) !== false) { - $key = trim(substr($value, 0, $pos)); - $value = trim(substr($value, $pos+1)); - $this->_cookies[$key] = $value; + // parse headers + $headers = array(); + $lines = explode($crlf, $header); + foreach($lines as $line) { + if(($pos = strpos($line, ':')) !== false) { + $key = strtolower(trim(substr($line, 0, $pos))); + $value = trim(substr($line, $pos+1)); + $headers[$key] = $value; + if(strcmp($key, "set-cookie") == 0) { + if(($pos = strpos($value, '=')) !== false) { + $key = trim(substr($value, 0, $pos)); + $value = trim(substr($value, $pos+1)); + $this->_cookies[$key] = $value; + } + } } } - } - } - // redirection? - if(isset($headers['location'])) - { - $http = new HTTPRequest($headers['location'], $this->_cookies); - return($http->DownloadToString()); - } - else - { - return($body); + // redirection? + if(isset($headers['location'])) + { + $http = new HTTPRequest($headers['location'], $this->_cookies); + return($http->DownloadToString()); + } + else + { + return($body); + } + } + else { + return(FALSE); + } + } catch (Exception $exception) { + $this->_errstr = $exception->getMessage(); + $this->_errno = $exception->getCode(); + return(FALSE); } } } From 37271ef45667bf6bbb4722faca2e880ff35cdb94 Mon Sep 17 00:00:00 2001 From: TJ Date: Fri, 7 Oct 2011 20:57:34 +0100 Subject: [PATCH 5/8] 4875: add error detection to IMS CC import; set default error values --- home/ims/ims_import.php | 3 ++- include/classes/HTTPRequest.class.php | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/home/ims/ims_import.php b/home/ims/ims_import.php index a1cd1e30..b02f8ac9 100644 --- a/home/ims/ims_import.php +++ b/home/ims/ims_import.php @@ -810,7 +810,8 @@ function glossaryCharacterData($parser, $data){ if (isset($_REQUEST['url']) && ($_REQUEST['url'] != 'http://') ) { $http_req = new HTTPRequest($_REQUEST['url'], array()); - if ($content = $http_req->DownloadToString()) { + $content = $http_req->DownloadToString(); + if (!$http_req->_errno && $content) { $filename = substr(time(), -6). '.zip'; $full_filename = TR_CONTENT_DIR . $filename; diff --git a/include/classes/HTTPRequest.class.php b/include/classes/HTTPRequest.class.php index d77e15ca..5158231d 100644 --- a/include/classes/HTTPRequest.class.php +++ b/include/classes/HTTPRequest.class.php @@ -15,8 +15,8 @@ class HTTPRequest var $_uri; // request URI var $_port; // port var $_cookies = array(); // array of cookies - var $_errstr; - var $_errno; + var $_errstr = ''; + var $_errno = 0; // scan url function _scan_url() @@ -126,7 +126,7 @@ function DownloadToString() } } catch (Exception $exception) { $this->_errstr = $exception->getMessage(); - $this->_errno = $exception->getCode(); + $this->_errno = $exception->getCode(); return(FALSE); } } From b840a91e290338ea656c58bdb0deb694f6e6a1c4 Mon Sep 17 00:00:00 2001 From: TJ Date: Sat, 8 Oct 2011 21:30:14 +0100 Subject: [PATCH 6/8] 4875: report HTTPRequest errors --- home/ims/ims_import.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/home/ims/ims_import.php b/home/ims/ims_import.php index b02f8ac9..0d0fba11 100644 --- a/home/ims/ims_import.php +++ b/home/ims/ims_import.php @@ -825,7 +825,10 @@ function glossaryCharacterData($parser, $data){ exit; } fclose($fp); - } + } + else { + $msg->addError(array('IMPORT_FAILED', $http_req->_errno . ": " . $http_req->_errstr)); + } $_FILES['file']['name'] = $filename; $_FILES['file']['tmp_name'] = $full_filename; $_FILES['file']['size'] = strlen($content); From d09c6421f8293c7d6d2ec5d5a97ec51cbc8f6947 Mon Sep 17 00:00:00 2001 From: TJ Date: Sun, 9 Oct 2011 00:56:52 +0100 Subject: [PATCH 7/8] 4875: give more useful error message to user --- home/ims/ims_import.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/home/ims/ims_import.php b/home/ims/ims_import.php index 0d0fba11..c31a9ade 100644 --- a/home/ims/ims_import.php +++ b/home/ims/ims_import.php @@ -827,7 +827,7 @@ function glossaryCharacterData($parser, $data){ fclose($fp); } else { - $msg->addError(array('IMPORT_FAILED', $http_req->_errno . ": " . $http_req->_errstr)); + $msg->addError(array('INVALID_INPUT', '"'.$_REQUEST['url'] . '" HTTPRequest error ' . $http_req->_errstr)); } $_FILES['file']['name'] = $filename; $_FILES['file']['tmp_name'] = $full_filename; From eb3f6eb226c4a8918beb9c30c5e5fafab230e6c1 Mon Sep 17 00:00:00 2001 From: TJ Date: Thu, 24 Nov 2011 13:10:02 +0000 Subject: [PATCH 8/8] 4875: Remove trailing line-feed from EOF Can sometimes cause premature sending of the HTTP Headers resulting in the user seeing blank pages instead of content. --- include/classes/HTTPRequest.class.php | 1 - 1 file changed, 1 deletion(-) diff --git a/include/classes/HTTPRequest.class.php b/include/classes/HTTPRequest.class.php index 5158231d..1be21562 100644 --- a/include/classes/HTTPRequest.class.php +++ b/include/classes/HTTPRequest.class.php @@ -132,4 +132,3 @@ function DownloadToString() } } ?> -