radowoj /
searcher
This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?php |
||
|
0 ignored issues
–
show
Coding Style
introduced
by
Loading history...
|
|||
| 2 | |||
| 3 | namespace Radowoj\Searcher\SearchProvider; |
||
| 4 | |||
| 5 | use stdClass; |
||
| 6 | |||
| 7 | use GuzzleHttp\Client as GuzzleClient; |
||
| 8 | use Psr\Http\Message\ResponseInterface as Psr7Response; |
||
| 9 | |||
| 10 | use Radowoj\Searcher\SearchResult\Collection; |
||
| 11 | use Radowoj\Searcher\SearchResult\ICollection; |
||
| 12 | use Radowoj\Searcher\SearchResult\Item; |
||
| 13 | use Radowoj\Searcher\SearchResult\IItem; |
||
| 14 | |||
| 15 | use Radowoj\Searcher\Exceptions\Exception; |
||
| 16 | use Radowoj\Searcher\Exceptions\QuotaExceededException; |
||
| 17 | use Radowoj\Searcher\Exceptions\RateLimitExceededException; |
||
| 18 | |||
| 19 | class Google extends SearchProvider implements ISearchProvider |
||
| 20 | {
|
||
| 21 | const URI = 'https://www.googleapis.com/customsearch/v1?'; |
||
| 22 | |||
| 23 | protected $apiKey = null; |
||
| 24 | |||
| 25 | protected $cx = null; |
||
| 26 | |||
| 27 | protected $guzzle = null; |
||
| 28 | |||
| 29 | 9 | public function __construct(GuzzleClient $guzzle, string $apiKey, string $cx) |
|
| 30 | {
|
||
| 31 | 9 | $this->apiKey = $apiKey; |
|
| 32 | 9 | $this->cx = $cx; |
|
| 33 | 9 | $this->guzzle = $guzzle; |
|
| 34 | 9 | } |
|
| 35 | |||
| 36 | |||
| 37 | 8 | protected function getSearchQueryString(string $query, int $limit, int $offset) |
|
|
0 ignored issues
–
show
|
|||
| 38 | {
|
||
| 39 | $params = [ |
||
| 40 | 8 | 'key' => $this->apiKey, |
|
| 41 | 8 | 'q' => urlencode($query), |
|
| 42 | 8 | 'cx' => $this->cx, |
|
| 43 | ]; |
||
| 44 | |||
| 45 | 8 | if ($offset) {
|
|
| 46 | 1 | $params['start'] = $offset; |
|
| 47 | } |
||
| 48 | |||
| 49 | 8 | $paramsMerged = []; |
|
| 50 | |||
| 51 | 8 | foreach($params as $key => $value) {
|
|
| 52 | 8 | $paramsMerged[] = "{$key}={$value}";
|
|
| 53 | } |
||
| 54 | |||
| 55 | 8 | return implode('&', $paramsMerged);
|
|
| 56 | } |
||
| 57 | |||
| 58 | |||
| 59 | 8 | protected function searchRequest(string $query, int $limit, int $offset) : stdClass |
|
| 60 | {
|
||
| 61 | 8 | $uri = self::URI . $this->getSearchQueryString($query, $limit, $offset); |
|
| 62 | |||
| 63 | 8 | $result = $this->guzzle->request( |
|
| 64 | 8 | 'GET', |
|
| 65 | $uri, [ |
||
| 66 | 8 | 'http_errors' => false, |
|
| 67 | ] |
||
| 68 | ); |
||
| 69 | |||
| 70 | 8 | return $this->decodeResponse($result); |
|
| 71 | } |
||
| 72 | |||
| 73 | |||
| 74 | /** |
||
| 75 | * Handle response based on HTTP status code (catches 400s - usually quota or rate limit, |
||
| 76 | * so authorisation errors and other stuff will be thrown as generic Searcher exception) |
||
| 77 | * |
||
| 78 | * On status == 200 it simply returns json-decoded response. |
||
| 79 | * |
||
| 80 | * @param Psr7Response $result result from Guzzle |
||
| 81 | * @return array |
||
| 82 | */ |
||
| 83 | 8 | protected function decodeResponse(Psr7Response $result) : stdClass |
|
| 84 | {
|
||
| 85 | 8 | $decodedResult = json_decode($result->getBody()); |
|
| 86 | 8 | switch($result->getStatusCode()) {
|
|
| 87 | 8 | case 200: |
|
| 88 | 6 | return $decodedResult; |
|
| 89 | 2 | case 403: |
|
|
0 ignored issues
–
show
The case body in a switch statement must start on the line following the statement.
According to the PSR-2, the body of a case statement must start on the line immediately following the case statement. switch ($expr) {
case "A":
doSomething(); //right
break;
case "B":
doSomethingElse(); //wrong
break;
} To learn more about the PSR-2 coding standard, please refer to the PHP-Fig. Loading history...
Terminating statement must be on a line by itself
As per the PSR-2 coding standard, the switch ($expr) {
case "A":
doSomething();
break; //wrong
case "B":
doSomething();
break; //right
case "C:":
doSomething();
return true; //right
}
To learn more about the PSR-2 coding standard, please refer to the PHP-Fig. Loading history...
|
|||
| 90 | 1 | throw new QuotaExceededException( |
|
| 91 | 1 | $decodedResult->error->message ?? $result->getReasonPhrase() |
|
| 92 | ); |
||
|
0 ignored issues
–
show
DEFAULT statements must be defined using a colon
As per the PSR-2 coding standard, default statements should not be wrapped in curly braces. switch ($expr) {
default: { //wrong
doSomething();
break;
}
}
switch ($expr) {
default: //right
doSomething();
break;
}
To learn more about the PSR-2 coding standard, please refer to the PHP-Fig. Loading history...
|
|||
| 93 | default: |
||
| 94 | 1 | throw new Exception("Google API responded with HTTP status {$result->getStatusCode()} - {$result->getReasonPhrase()}");
|
|
| 95 | } |
||
| 96 | } |
||
| 97 | |||
| 98 | |||
| 99 | 5 | protected function enforceLimit(stdClass $result, int $limit) : stdClass |
|
| 100 | {
|
||
| 101 | 5 | if (!isset($result->items)) {
|
|
| 102 | 1 | return $result; |
|
| 103 | } |
||
| 104 | 4 | $result->items = array_slice($result->items, 0, $limit); |
|
| 105 | 4 | return $result; |
|
| 106 | } |
||
| 107 | |||
| 108 | |||
| 109 | 6 | protected function validateRequestResult(stdClass $result) |
|
| 110 | {
|
||
| 111 | 6 | if (!isset($result->kind) || $result->kind !== "customsearch#search") {
|
|
| 112 | 1 | throw new Exception("Invalid Google API response: " . print_r($result, 1));
|
|
| 113 | } |
||
| 114 | 5 | } |
|
| 115 | |||
| 116 | |||
| 117 | 5 | protected function extractResults(stdClass $result) : array |
|
| 118 | {
|
||
| 119 | 5 | return isset($result->items) |
|
| 120 | 4 | ? $result->items |
|
| 121 | 5 | : []; |
|
| 122 | } |
||
| 123 | |||
| 124 | |||
| 125 | 5 | protected function extractTotalMatches(stdClass $result) : int |
|
| 126 | {
|
||
| 127 | 5 | return isset($result->searchInformation->totalResults) |
|
| 128 | 4 | ? $result->searchInformation->totalResults |
|
| 129 | 5 | : 0; |
|
| 130 | } |
||
| 131 | |||
| 132 | |||
| 133 | 1 | protected function populateItem(stdClass $item) : IItem |
|
| 134 | {
|
||
| 135 | 1 | return new Item([ |
|
| 136 | 1 | 'url' => $item->link, |
|
| 137 | 1 | 'title' => $item->title, |
|
| 138 | 1 | 'description' => $item->snippet, |
|
| 139 | ]); |
||
| 140 | } |
||
| 141 | |||
| 142 | } |
||
| 143 |