Update PHP version to 8.1.3
dimitryzub opened this issue ยท 4 comments
Throws an error when updating google-search-results-php
to latest 2.0
version.
Local version is 1.2.0
:
$ composer show
serpapi/google-search-results-php 1.2.0 Google search result via Serp API
Updating via composer to version 2.0
:
$ composer require serpapi/google-search-results-php:2.0
Error:
- serpapi/google-search-results-php 2.0 requires php ^5.5 || ^7.0 -> your php version (8.1.3) does not satisfy that requirement.
Installation failed, reverting ./composer.json and ./composer.lock to their original content.
Pretty much a duplicate of PHP 8 #7 issue.
+1 need this package for php 8.1
With @marm123 we have noticed that when running this library on PHP version 8.x the following error is appearing:
Return type of RestClient::current() should either be compatible with Iterator::current(): mixed, or the #[\\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice
I found out that restclient.php
is not compatible with PHP version 8.x
The temporary solution just replaces the restclient.php
with the following:
<?php
/**
* PHP REST Client
* https://github.com/tcdent/php-restclient
* (c) 2013-2017 Travis Dent <tcdent@gmail.com>
*/
class RestClientException extends Exception {}
class RestClient implements Iterator, ArrayAccess {
public $options;
public $handle; // cURL resource handle.
// Populated after execution:
public $response; // Response body.
public $headers; // Parsed reponse header object.
public $info; // Response info object.
public $error; // Response error string.
public $response_status_lines; // indexed array of raw HTTP response status lines.
// Populated as-needed.
public $decoded_response; // Decoded response body.
public function __construct($options=[]){
$default_options = [
'headers' => [],
'parameters' => [],
'curl_options' => [],
'build_indexed_queries' => FALSE,
'user_agent' => "PHP RestClient/0.1.7",
'base_url' => NULL,
'format' => NULL,
'format_regex' => "/(\w+)\/(\w+)(;[.+])?/",
'decoders' => [
'json' => 'json_decode',
'php' => 'unserialize'
],
'username' => NULL,
'password' => NULL
];
$this->options = array_merge($default_options, $options);
if(array_key_exists('decoders', $options))
$this->options['decoders'] = array_merge(
$default_options['decoders'], $options['decoders']);
}
public function set_option($key, $value){
$this->options[$key] = $value;
}
public function register_decoder($format, $method){
// Decoder callbacks must adhere to the following pattern:
// array my_decoder(string $data)
$this->options['decoders'][$format] = $method;
}
#[\ReturnTypeWillChange]
// Iterable methods:
public function rewind(){
$this->decode_response();
return reset($this->decoded_response);
}
#[\ReturnTypeWillChange]
public function current(){
return current($this->decoded_response);
}
#[\ReturnTypeWillChange]
public function key(){
return key($this->decoded_response);
}
#[\ReturnTypeWillChange]
public function next(){
return next($this->decoded_response);
}
#[\ReturnTypeWillChange]
public function valid(){
return is_array($this->decoded_response)
&& (key($this->decoded_response) !== NULL);
}
#[\ReturnTypeWillChange]
// ArrayAccess methods:
public function offsetExists($key){
$this->decode_response();
return is_array($this->decoded_response)?
isset($this->decoded_response[$key]) : isset($this->decoded_response->{$key});
}
#[\ReturnTypeWillChange]
public function offsetGet($key){
$this->decode_response();
if(!$this->offsetExists($key))
return NULL;
return is_array($this->decoded_response)?
$this->decoded_response[$key] : $this->decoded_response->{$key};
}
#[\ReturnTypeWillChange]
public function offsetSet($key, $value){
throw new RestClientException("Decoded response data is immutable.");
}
#[\ReturnTypeWillChange]
public function offsetUnset($key){
throw new RestClientException("Decoded response data is immutable.");
}
// Request methods:
public function get($url, $parameters=[], $headers=[]){
return $this->execute($url, 'GET', $parameters, $headers);
}
public function post($url, $parameters=[], $headers=[]){
return $this->execute($url, 'POST', $parameters, $headers);
}
public function put($url, $parameters=[], $headers=[]){
return $this->execute($url, 'PUT', $parameters, $headers);
}
public function patch($url, $parameters=[], $headers=[]){
return $this->execute($url, 'PATCH', $parameters, $headers);
}
public function delete($url, $parameters=[], $headers=[]){
return $this->execute($url, 'DELETE', $parameters, $headers);
}
public function head($url, $parameters=[], $headers=[]){
return $this->execute($url, 'HEAD', $parameters, $headers);
}
public function execute($url, $method='GET', $parameters=[], $headers=[]){
$client = clone $this;
$client->url = $url;
$client->handle = curl_init();
$curlopt = [
CURLOPT_HEADER => TRUE,
CURLOPT_RETURNTRANSFER => TRUE,
CURLOPT_USERAGENT => $client->options['user_agent']
];
if($client->options['username'] && $client->options['password'])
$curlopt[CURLOPT_USERPWD] = sprintf("%s:%s",
$client->options['username'], $client->options['password']);
if(count($client->options['headers']) || count($headers)){
$curlopt[CURLOPT_HTTPHEADER] = [];
$headers = array_merge($client->options['headers'], $headers);
foreach($headers as $key => $values){
foreach(is_array($values)? $values : [$values] as $value){
$curlopt[CURLOPT_HTTPHEADER][] = sprintf("%s:%s", $key, $value);
}
}
}
if($client->options['format'])
$client->url .= '.'.$client->options['format'];
// Allow passing parameters as a pre-encoded string (or something that
// allows casting to a string). Parameters passed as strings will not be
// merged with parameters specified in the default options.
if(is_array($parameters)){
$parameters = array_merge($client->options['parameters'], $parameters);
$parameters_string = http_build_query($parameters);
// http_build_query automatically adds an array index to repeated
// parameters which is not desirable on most systems. This hack
// reverts "key[0]=foo&key[1]=bar" to "key[]=foo&key[]=bar"
if(!$client->options['build_indexed_queries'])
$parameters_string = preg_replace(
"/%5B[0-9]+%5D=/simU", "%5B%5D=", $parameters_string);
}
else
$parameters_string = (string) $parameters;
if(strtoupper($method) == 'POST'){
$curlopt[CURLOPT_POST] = TRUE;
$curlopt[CURLOPT_POSTFIELDS] = $parameters_string;
}
elseif(strtoupper($method) != 'GET'){
$curlopt[CURLOPT_CUSTOMREQUEST] = strtoupper($method);
$curlopt[CURLOPT_POSTFIELDS] = $parameters_string;
}
elseif($parameters_string){
$client->url .= strpos($client->url, '?')? '&' : '?';
$client->url .= $parameters_string;
}
if($client->options['base_url']){
if($client->url[0] != '/' && substr($client->options['base_url'], -1) != '/')
$client->url = '/' . $client->url;
$client->url = $client->options['base_url'] . $client->url;
}
$curlopt[CURLOPT_URL] = $client->url;
if($client->options['curl_options']){
// array_merge would reset our numeric keys.
foreach($client->options['curl_options'] as $key => $value){
$curlopt[$key] = $value;
}
}
curl_setopt_array($client->handle, $curlopt);
$client->parse_response(curl_exec($client->handle));
$client->info = (object) curl_getinfo($client->handle);
$client->error = curl_error($client->handle);
curl_close($client->handle);
return $client;
}
public function parse_response($response){
$headers = [];
$this->response_status_lines = [];
$line = strtok($response, "\n");
do {
if(strlen(trim($line)) == 0){
// Since we tokenize on \n, use the remaining \r to detect empty lines.
if(count($headers) > 0) break; // Must be the newline after headers, move on to response body
}
elseif(strpos($line, 'HTTP') === 0){
// One or more HTTP status lines
$this->response_status_lines[] = trim($line);
}
else {
// Has to be a header
list($key, $value) = explode(':', $line, 2);
$key = trim(strtolower(str_replace('-', '_', $key)));
$value = trim($value);
if(empty($headers[$key]))
$headers[$key] = $value;
elseif(is_array($headers[$key]))
$headers[$key][] = $value;
else
$headers[$key] = [$headers[$key], $value];
}
} while($line = strtok("\n"));
$this->headers = (object) $headers;
$this->response = strtok("");
}
public function get_response_format(){
if(!$this->response)
throw new RestClientException(
"A response must exist before it can be decoded.");
// User-defined format.
if(!empty($this->options['format']))
return $this->options['format'];
// Extract format from response content-type header.
if(!empty($this->headers->content_type))
if(preg_match($this->options['format_regex'], $this->headers->content_type, $matches))
return $matches[2];
throw new RestClientException(
"Response format could not be determined.");
}
public function decode_response(){
if(empty($this->decoded_response)){
$format = $this->get_response_format();
if(!array_key_exists($format, $this->options['decoders']))
throw new RestClientException("'${format}' is not a supported ".
"format, register a decoder to handle this response.");
$this->decoded_response = call_user_func(
$this->options['decoders'][$format], $this->response);
}
return $this->decoded_response;
}
}
Restclient is compatible with PHP 8.1: https://github.com/tcdent/php-restclient/releases/tag/0.1.8
The problem is we commit restclient.php
instead of using composer for it:
google-search-results-php/composer.json
Line 55 in 9d3112f
@jvmvik I'd like to install restclient from composer. wdyt?
Restclient is compatible with PHP 8.1: https://github.com/tcdent/php-restclient/releases/tag/0.1.8
The problem is we commit
restclient.php
instead of using composer for it:google-search-results-php/composer.json
Line 55 in 9d3112f
@jvmvik I'd like to install restclient from composer. wdyt?
Yes, our restclient is outdated 2017 - either we update it in our library or we use composer.