HTTP Requests
In Jalno, the packages\base\http\Client class has been created for making HTTP requests. Using other libraries, this class can create a POST or GET HTTP request.
Currently, Jalno only uses the CURL library to create requests; for this purpose, the packages\base\http\CURL class has been created.
Using Client instead of using the CURL class directly allows you to add a new library at any time and use it thereafter, without changing your code.
Introduction to the CURL Library
In PHP, various methods and functions such as file_get_contents("http://www.google.com") are used to fetch the contents of a page. However, sometimes it is necessary to use cookies while fetching a page, or to send data to a form, or to perform authentication. To carry out this category of operations in PHP, the CURL library has been created.
Creating a Request
To create a request, you first need to create an object of the packages\base\http\Client class.
A request can be one of the get or post types. For this purpose, two methods, get and post, have been created in the Client class, and the relevant method is called according to the request type.
The get and post methods take two input arguments. The first argument is the URL, which must be entered in full, and the second argument is an array of request options.
The output of these methods is an object of the packages\base\http\Response class.
When working with the Client class, it is better to use logs so that, if needed, you can easily debug the program.
For more information, refer to the Logs page.
Example
namespace packages\packagename\controllers;
use packages\base\{Controller, Log, Http};
class Main extends Controller
{
public function getGoogle()
{
$log = Log::getInstance();
$client = new Http\Client();
try {
$log->info("init client params");
$params = [
"timeout" => 10
];
$log->reply($params);
$log->info("send http request to get http://www.google.com");
$response = $client->get("http://www.google.com", $params);
echo $response->getbody();
} catch (Http\ClientException $e) {
echo "Error {$e->getResponse()->getStatusCode()} has occurred";
} catch (Http\ServerException $e) {
echo "Error {$e->getResponse()->getStatusCode()} has occurred";
}
}
}
In the example above, the first page of Google is fetched, and by calling the getbody() method, which is defined in the Response class, you can display it.
If the execution does not proceed correctly and an exception is thrown, it displays the error status code.
Exceptions
When sending a request, a problem may occur on the server or client side that prevents the execution from proceeding correctly. The problems that arise cause the packages\base\http\ServerException or packages\base\http\ClientException exceptions to be thrown.
For requests whose status is 4xx, the ClientException is thrown, and for requests whose status is 5xx, the ServerException is thrown.
In the ClientException and ServerException exceptions, two methods, getResponse() and getRequest(), are defined, which return an object of the Response and Request classes respectively. By calling them on the exception object, you can access the information of the sent request and its response that caused the exception, such as the error status code.
Request Options
When creating a request, you need to set some options for it, which are also of great importance.
The options are passed as an array to the second argument of the get and post methods.
The options you can define for a request are as follows.
| Option | Description |
|---|---|
base_uri | Specifies the main domain of the site. |
allow_redirects | Permission to follow the pages that the server sends as part of the HTTP header. Its default value is true. |
auth | An array of authentication credentials. |
cookies | Permission to store cookies, or specifying the path of the cookie file. |
connect_timeout | The waiting time to connect to the server, in seconds. |
delay | Creating a delay in the execution process, in microseconds. |
form_params | Sending text data. |
headers | Registering the request header parameters. |
json | Sending data in JSON format. |
multipart | Sending a file. |
proxy | An array of proxy credentials. |
query | An array of variables that are added to the URL. |
ssl_verify | Verifying the site's certificate (the default value is true). |
timeout | The waiting time to receive a response, in seconds. |
save_as | Specifying the storage location of the downloaded file. |
outgoing_ip | Specifying the IP for servers that have multiple IP addresses. |
auth
Connecting to some servers requires a username and password for authentication. For this purpose, the auth key receives a value for the Authorization key in the request header.
If the auth key is set as an array with the username and password keys, the Authorization key in the request header is set as an encoded value.
$params = [
"auth" => [
"username" => "ali",
"password" => 1234578,
],
];
/**
* Output like
* Authorization: Basic YWxpOjEyMzQ1Nzg=
*/
If the auth key is set as a string, it is added to the request header without any processing.
$params = [
"auth" => "Basic dXNlcm5hbWU6cGFzc3dvcmQ=",
];
/**
* Output like
* Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=
*/
headers
Every request that is sent has a header that specifies information related to the request, such as the format of the data being sent, the date, and so on.
headers['content-type'] specifies the format of the data being sent, which by default is text/plain. The content-type value is set by the framework according to the json, form_params, and multipart keys.
In each request, you must set only one of the json, form_params, or multipart keys.
cookies
The cookies key is used to enable or disable storing cookies. The default value of this key is true, and the cookie file is stored in the project's root directory. If we do not want the cookies to be stored, we set the key value to false. If we want to change the storage location of the cookie file, we pass the desired file path to the key as a string.
$params = [
'cookies' => '/tmp/cookies.txt'
];
form_params
The form_params key is used to send text data, and it receives a key-value array.
The entered values are added to the body key and sent when the request is dispatched.
If you have set the form_params key in the request, you must not also set the multipart and json keys.
$params = [
'form_params' => [
'keyOne' => 'valueOne',
'keyTwo' => 'valueTwo'
]
];
multipart
To upload a file, the header must specify that the sent content includes a file. For this purpose, the multipart key is used.
This key takes a key-value array with file values. If string data also needs to be sent, it must be defined within this same key.
When you set the multipart key, the framework sets the value of headers['content-type'] to multipart/form-data.
The entered values are added to the body key and sent when the request is dispatched.
If you have set the multipart key in the request, you must not also set the form_params and json keys.
$params = [
'multipart' => [
'image' => new File\Loca("packages/packagename/image/img.jpg"),
'pdf' => new File\Loca("packages/packagename/files/file.pdf"),
'title' => 'files of packagename'
]
];
proxy
Sometimes it is necessary to use a proxy to connect to certain servers. To configure the proxy, the host address, port, and, if needed, the username and password must be passed as an array to the proxy key.
$params = [
'proxy' => [
'hostname' => '1.2.3.4',
'port' => 123,
'username' => 'ali',
'password' => '12345678'
]
];
save_as
For requests that are sent to download a file, the storage location of the file must also be specified in the save_as key. The input of this key is an object of the File class.
$params = [
'save_as' => new File\Local("/tmp/download/file.format")
];
json
The json key is used to send data in JSON format.
This key receives an array of values as key-value pairs, and the framework automatically converts them to JSON format.
When you set the json key, the framework sets the value of headers['content-type'] to application/json.
The entered values are added to the body key and sent when the request is dispatched.
If you have set the json key in the request, you must not also set the form_params and multipart keys.
$params = [
'form_params' => [
'keyOne' => 'valueOne',
'keyTwo' => 'valueTwo'
]
];
base_uri
You may want to send several requests to different pages of a single site. In this case, you can pass the site's domain address to the base_uri key and pass the desired page address to the first argument of the get and post methods.
You can also set the domain address when creating the object instead of setting the base_uri key.
$client = new Client();
$params = [
'base_uri' => 'http://www.example.com/',
'form_params' => [
'username' => 'john',
'password' => 12345678
]
];
$client->post('userpanel/login', $params);
$client->get('userpanel/documents', [
'save_as' => new File\Local("/tmp/download/doc.pdf")
]);
$client = new Client(array(
'base_uri' => 'http://www.example.com/',
));
$client->post('register', [
'json' => [
'name' => "John",
'password' => '000',
]
]);
$client->get('userpanel/tickets', ["query" => ["ajax" => 1]]);
A Few Examples
Example 1
namespace packages\packagename\controllers;
use packages\base\{Controller, Log, IO\File, Http};
class FileManager extends Controller
{
public function downloadPHPDoc(File $source)
{
$log = Log::getInstance();
$sourceDirectory = $source->getDirectory();
if (!$sourceDirectory->exists()) {
$sourceDirectory->make(true);
}
$client = new Http\Client();
try {
$log->info("init client params");
$params = array(
"ssl_verify" => false,
"cookies" => false,
"save_as" => $source
);
$log->reply($params);
$log->info("send http request for download php_manual_en.html.gz from php.net");
$response = $client->get("https://www.php.net/distributions/manual/php_manual_en.html.gz", $params);
} catch (Http\ClientException $e) {
echo "Error {$e->getResponse()->getStatusCode()} has occurred";
} catch (Http\ServerException $e) {
echo "Error {$e->getResponse()->getStatusCode()} has occurred";
}
}
}
The code above downloads a file in gz format. The file is stored at the location specified by the input of the downloadPHPDoc method, $source, which is passed to the save_as key.
Example 2
namespace packages\packagename\controllers;
use packages\base\{Controller, Log, IO\File, Http};
class FileManager extends Controller
{
public function download(string $filePath, File $source, array $auth, string $url)
{
$log = Log::getInstance();
$log->info("insure the source directory is exists");
$sourceDirectory = $source->getDirectory();
if (!$sourceDirectory->exists()) {
$sourceDirectory->make(true);
}
$log->info("send http client request to {$username}@", $url, " for download ", $filePath);
$client = new Http\Client();
try {
$log->info("init client params");
$params = array(
"ssl_verify" => false,
"cookies" => "/tmp/cookies.txt",
"save_as" => $source,
"auth" => array(
"username" => $auth['username'],
"password" => $auth['password'],
),
"query" => array(
"path" => $filePath
),
);
$log->reply($params);
$response = $client->get($url, $params);
} catch (Http\ClientException $e) {
echo "Error {$e->getResponse()->getStatusCode()} has occurred";
} catch (Http\ServerException $e) {
echo "Error {$e->getResponse()->getStatusCode()} has occurred";
}
}
}
In the example above, authentication is required to download the file from the server. The username and password are specified in the auth key.
The download file path is specified in the path parameter, which is appended to the url.
The storage path of the cookie file is specified in the cookies key.
Example 3
namespace packages\packagename\controllers;
use packages\base\{Controller, Log, IO\File, Http, Exception};
class FileManager extends Controller
{
public function upload(array $auth, string $url)
{
$log = Log::getInstance();
if (!$source->exists()) {
throw new Exception("file not exists");
}
$client = new Http\Client();
try {
$log->info("init client params");
$params = array(
"ssl_verify" => false,
"cookies" => false,
'proxy' => [
'hostname' => '1.2.3.4',
'port' => 123,
'username' => 'ali',
'password' => '12345678'
],
'multipart' => [
'file' => new File\Local("packages/packagename/doc.pdf")
]
);
$response = $client->post($url, $params);
} catch (Http\ClientException $e) {
echo "Error {$e->getResponse()->getStatusCode()} has occurred";
} catch (Http\ServerException $e) {
echo "Error {$e->getResponse()->getStatusCode()} has occurred";
}
}
}
In the code above, the user connects to the specified proxy, and then the file passed to the multipart key is sent to the $url server.
Example 4
namespace packages\packagename\controllers;
use packages\base\{Controller, Log, Http};
class Main extends Controller
{
public function sendInfo(string $name, string $city, int $age)
{
$log = Log::getInstance();
$client = new Http\Client();
try {
$log->info("init client params");
$params = array(
"ssl_verify" => true,
"cookies" => false,
'form_params' => [
'name' => $name,
'city' => $city,
'age' => $age
]
);
$response = $client->post("https://www.example.com", $params);
} catch (Http\ClientException $e) {
echo "Error {$e->getResponse()->getStatusCode()} has occurred";
} catch (Http\ServerException $e) {
echo "Error {$e->getResponse()->getStatusCode()} has occurred";
}
}
}
Example 5
namespace packages\packagename\controllers;
use packages\base\{Controller, Log, Http};
class Users extends Controller
{
public function register(array $info)
{
$log = Log::getInstance();
$client = new Http\Client("https://www.example.com");
try {
$log->info("init client params for register");
$params = array(
"ssl_verify" => true,
"cookies" => false,
'json' => [
'username' => $info['username'],
'password' => $info['password'],
'email' => $info['email']
]
);
$response = $client->post('register', $params);
$log->info("init client params for complete profile");
$params = array(
"ssl_verify" => true,
"cookies" => false,
'form_params' => [
'name' => $info['name'],
'city' => $info['city'],
'age' => $info['age'],
'address' => $info['address']
],
'query' => [
'user' => $info['username']
]
);
$response = $client->post('userpanel/profile', $params);
} catch (Http\ClientException $e) {
echo "Error {$e->getResponse()->getStatusCode()} has occurred";
} catch (Http\ServerException $e) {
echo "Error {$e->getResponse()->getStatusCode()} has occurred";
}
}
}
The Response Class
HTTP requests are sent by calling the get and post methods of the Client class. The output of these methods is an object of the packages\base\http\Response class.
By calling the methods of the Response class, you can access information such as the status code, the response header, and the data sent from the server.
Also, in the thrown exceptions, by calling the getResponse() method on the exception object, you can access the Response class.
The methods of this class are as follows.
| Method | Description |
|---|---|
getStatusCode() | Reads the status code. |
getHeader($name) | Reads one of the header parameters. |
getHeaders() | Reads the header parameters. |
getBody() | Receives the data sent from the server. |
getPrimaryIP() | Reads the IP. |
Example
namespace packages\packagename\controllers;
use packages\base\{Controller, Log, Http};
class Main extends Controller
{
public function register(string $name, string $email)
{
$log = Log::getInstance();
$client = new Http\Client();
try {
$log->info("init client params");
$params = array(
"ssl_verify" => true,
"cookies" => false,
'json' => [
'name' => $name,
'email' => $email
]
);
$response = $client->post("https://www.example.com", $params);
print_r($response->getHeader("date"));
print_r($response->getBody());
/**
* output:
* Fri, 20 Nov 2020 17:25:27 GMT
* Array
* (
* [status] => your register is completed.
* )
*/
} catch (Http\ClientException $e) {
echo "Error {$e->getResponse()->getStatusCode()} has occurred";
} catch (Http\ServerException $e) {
echo "Error {$e->getResponse()->getStatusCode()} has occurred";
}
}
}
The Request Class
When a request is sent, the framework creates an object of the packages\base\http\Request class.
If the execution does not proceed correctly and an exception is thrown, you can access the Request class by calling the getRequest() method on the exception object, and inspect the sent request by calling the methods defined in the class.
The methods of this class are as follows.
| Method | Description |
|---|---|
getMethod() | The request type (GET or POST). |
getHost() | Gets the host part of the address. |
getURI() | Gets the URI part of the address. |
getQuery() | Gets the address parameters. |
getURL() | Gets the full address. |
getPort() | Gets the port. |
getIP() | Gets the IP. |
getHeader(string $name) | Gets a specific header parameter. |
getHeaders() | Gets the header parameters. |
getBody() | Gets the data sent in the request. |
getProxy() | Gets the configured proxy. |
getSaveAs() | Gets the file specified for storing the downloaded file. |
getOutgoingIP() | Gets the IP specified from among the server's IP addresses. |
Example
namespace packages\packagename\controllers;
use packages\base\{Controller, Log, Http};
class Main extends Controller
{
public function register(string $name, string $email)
{
$log = Log::getInstance();
$client = new Http\Client();
try {
$log->info("init client params");
$params = array(
"ssl_verify" => true,
"cookies" => false,
'json' => [
'name' => $name,
'email' => $email
]
);
$response = $client->post("https://www.example.com", $params);
} catch (Http\ClientException $e) {
print_r($e->getRequest()->getHeaders());
print_r($e->getRequest()->getBody());
} catch (Http\ServerException $e) {
echo "URL: {$e->getRequest()->getURL()}";
}
}
}