Skip to content
This repository was archived by the owner on Jun 27, 2018. It is now read-only.

Commit 6c5a558

Browse files
committed
Added support for using custom HTTP clients in a backward-compatible way.
Also added a test suite that covers the HTTPMessage and client classes.
1 parent c9cbfdd commit 6c5a558

File tree

12 files changed

+579
-138
lines changed

12 files changed

+579
-138
lines changed

.editorconfig

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# EditorConfig is awesome: http://EditorConfig.org
2+
3+
# top-most EditorConfig file
4+
root = true
5+
6+
# Unix-style newlines with a newline ending for every file
7+
# Indent with 4 spaces
8+
[php]
9+
end_of_line = lf
10+
indent_style = space
11+
indent_size = 4

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
phpunit.xml
2+
composer.phar
3+
composer.lock
4+
vendor/
5+
build/
6+
.idea
7+
.DS_STORE

composer.json

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "imsglobal/lti",
33
"version" : "3.0.2",
44
"description": "LTI Tool Provider Library",
5-
"keywords": ["lti"],
5+
"keywords": ["lti", "ims", "content-item", "edtech", "education", "lms"],
66
"homepage": "https://www.imsglobal.org/lti",
77
"type": "library",
88
"license": "Apache-2.0",
@@ -19,5 +19,19 @@
1919
"psr-4": {
2020
"IMSGlobal\\LTI\\": "src/"
2121
}
22+
},
23+
"require-dev": {
24+
"ext-curl": "*",
25+
"phpunit/phpunit": "^5.6"
26+
},
27+
"autoload-dev":{
28+
"psr-4": {
29+
"IMSGlobal\\LTI\\Test\\": "tests/"
30+
}
31+
},
32+
"scripts": {
33+
"test": "phpunit",
34+
"coverage": "phpunit --coverage-html=build/coverage",
35+
"coverage-text": "phpunit --coverage-text"
2236
}
2337
}

phpunit.xml.dist

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<phpunit bootstrap="./vendor/autoload.php"
3+
forceCoversAnnotation="true">
4+
5+
<testsuites>
6+
<testsuite>
7+
<directory suffix="Test.php">tests/</directory>
8+
</testsuite>
9+
</testsuites>
10+
11+
<filter>
12+
<whitelist addUncoveredFilesFromWhitelist="true">
13+
<directory suffix=".php">src</directory>
14+
</whitelist>
15+
</filter>
16+
17+
<php>
18+
<server name="TEST_SERVER_PORT" value="9999"/>
19+
</php>
20+
21+
</phpunit>

src/HTTP/Client.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
namespace IMSGlobal\LTI\HTTP;
4+
5+
use IMSGlobal\LTI\HTTPMessage;
6+
7+
/**
8+
* An HTTP client for sending the HTTP messages.
9+
*
10+
* @author Stephen P Vickers <[email protected]>
11+
* @copyright IMS Global Learning Consortium Inc
12+
* @date 2016
13+
* @version 3.0.0
14+
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
15+
*/
16+
interface Client
17+
{
18+
19+
/**
20+
* Send the provided HTTPMessage and then updates it with the response data.
21+
*
22+
* @param HTTPMessage $message The HTTP message to send
23+
* @return bool If successful, returns true
24+
*/
25+
public function send(HTTPMessage $message);
26+
27+
}

src/HTTP/CurlClient.php

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
<?php
2+
3+
namespace IMSGlobal\LTI\HTTP;
4+
5+
use IMSGlobal\LTI\HTTPMessage;
6+
7+
/**
8+
* Sends HTTP messages with cURL.
9+
*
10+
* @author Stephen P Vickers <[email protected]>
11+
* @copyright IMS Global Learning Consortium Inc
12+
* @date 2016
13+
* @version 3.0.0
14+
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
15+
*/
16+
class CurlClient implements Client
17+
{
18+
19+
/**
20+
* @inheritdoc
21+
*/
22+
public function send(HTTPMessage $message)
23+
{
24+
$message->ok = false;
25+
26+
$resp = '';
27+
$ch = curl_init();
28+
curl_setopt($ch, CURLOPT_URL, $message->url);
29+
if (!empty($message->requestHeaders)) {
30+
curl_setopt($ch, CURLOPT_HTTPHEADER, $message->requestHeaders);
31+
} else {
32+
curl_setopt($ch, CURLOPT_HEADER, 0);
33+
}
34+
if ($message->method === 'POST') {
35+
curl_setopt($ch, CURLOPT_POST, true);
36+
curl_setopt($ch, CURLOPT_POSTFIELDS, $message->request);
37+
} else if ($message->method !== 'GET') {
38+
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $message->method);
39+
if (!is_null($message->request)) {
40+
curl_setopt($ch, CURLOPT_POSTFIELDS, $message->request);
41+
}
42+
}
43+
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
44+
curl_setopt($ch, CURLINFO_HEADER_OUT, true);
45+
curl_setopt($ch, CURLOPT_HEADER, true);
46+
$chResp = curl_exec($ch);
47+
$message->ok = $chResp !== false;
48+
if ($message->ok) {
49+
$chResp = str_replace("\r\n", "\n", $chResp);
50+
$chRespSplit = explode("\n\n", $chResp, 2);
51+
if ((count($chRespSplit) > 1) && (substr($chRespSplit[1], 0, 5) === 'HTTP/')) {
52+
$chRespSplit = explode("\n\n", $chRespSplit[1], 2);
53+
}
54+
$message->responseHeaders = $chRespSplit[0];
55+
$resp = $chRespSplit[1];
56+
$message->status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
57+
$message->ok = $message->status < 400;
58+
if (!$message->ok) {
59+
$message->error = curl_error($ch);
60+
}
61+
}
62+
$message->requestHeaders = str_replace("\r\n", "\n", curl_getinfo($ch, CURLINFO_HEADER_OUT));
63+
curl_close($ch);
64+
$message->response = $resp;
65+
66+
return $message->ok;
67+
}
68+
69+
}

src/HTTP/StreamClient.php

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
3+
namespace IMSGlobal\LTI\HTTP;
4+
5+
use IMSGlobal\LTI\HTTPMessage;
6+
7+
/**
8+
* Sends HTTP messages with streams via fopen.
9+
*
10+
* @author Stephen P Vickers <[email protected]>
11+
* @copyright IMS Global Learning Consortium Inc
12+
* @date 2016
13+
* @version 3.0.0
14+
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
15+
*/
16+
class StreamClient implements Client
17+
{
18+
19+
/**
20+
* @inheritdoc
21+
*/
22+
public function send(HTTPMessage $message)
23+
{
24+
$message->ok = false;
25+
26+
// Prepare options for the HTTP context.
27+
$opts = array(
28+
'method' => $message->method,
29+
'content' => $message->request
30+
);
31+
if (!empty($message->requestHeaders)) {
32+
$opts['header'] = $message->requestHeaders;
33+
}
34+
35+
// Send the request.
36+
$http_response_header = null;
37+
$context = stream_context_create(['http' => $opts]);
38+
$stream = @fopen($message->url, 'rb', false, $context);
39+
if ($stream) {
40+
$message->response = @stream_get_contents($stream);
41+
fclose($stream);
42+
}
43+
44+
// Read the headers to get the status.
45+
if ($http_response_header) {
46+
$message->responseHeaders = implode("\n", $http_response_header);
47+
$parts = explode(' ', $message->responseHeaders, 3);
48+
$message->status = $parts[1];
49+
$message->ok = $message->status < 400;
50+
}
51+
52+
return $message->ok;
53+
}
54+
55+
}

0 commit comments

Comments
 (0)