GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

Search::getParams()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 0
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
1
<?php namespace zServices\ReceitaFederal\Services\Portais\AN;
2
3
use Captcha\Interfaces\ServiceInterface;
4
use zServices\Miscellany\ClientHttp;
5
use zServices\Miscellany\Curl;
6
use zServices\Miscellany\Exceptions\NoCaptchaResponse;
7
use zServices\Miscellany\Exceptions\NoServiceCall;
8
use zServices\Miscellany\Exceptions\NoServiceResponse;
9
use zServices\Miscellany\Interfaces\SearchInterface;
10
use zServices\ReceitaFederal\Services\Portais\AN\Crawler;
11
12
/**
13
 *
14
 */
15
class Search implements SearchInterface {
16
	/**
17
	 * Armazena a instãncia atual do request no serviço
18
	 * @var object
19
	 */
20
	private $instanceResponse;
21
22
	/**
23
	 * Armazena o cookie atual
24
	 * @var string
25
	 */
26
	private $cookie;
27
28
	/**
29
	 * Captcha request response
30
	 * @var string
31
	 */
32
	private $captcha;
33
34
	/**
35
	 * Armazena o base64 da imagem do captcha
36
	 * @var string base64
37
	 */
38
	private $captchaImage;
39
40
	/**
41
	 * @var object zServices\Sintegra\Services\ClientHttp
42
	 */
43
	private $client;
44
45
	/**
46
	 * Armazena as configurações para as requisições e crawler
47
	 * @var array
48
	 */
49
	private $configurations;
50
51
	/**
52
	 * [$params description]
53
	 * @var array
54
	 */
55
	private $params = [];
56
57
	/**
58
	 * decaptcher instance
59
	 * @var \Captcha\Interfaces\ServiceInterface
60
	 */
61
	public $decaptcher;
62
63
	/**
64
	 * Antes de chamar o cookie e o captcha, é preciso efetuar uma requisição
65
	 * primária no serviço. Capturando tais informações.
66
	 * Este método deverá fazer essa requisição, armazenando o request
67
	 * para os método como cookie e captcha prepararem suas informações
68
	 *
69
	 * @param  array $configurations  @ref zServices\Sintegra\Services\Sintegra\{Service}\Service::$configurations
70
	 * @return Search
71
	 */
72 View Code Duplication
	public function request($configurations) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
73
		$this->configurations = $configurations;
74
75
		// instancia o client http
76
		$this->client = new ClientHttp();
77
78
		// Executa um request para URL do serviço, retornando o cookie da requisição primária
79
		$this->instanceResponse = $this->client->request('GET', $this->configurations['home']);
80
81
		// Captura o cookie da requisição, será usuado posteriormente
82
		$this->cookie = $this->client->cookie();
83
84
		return $this;
85
	}
86
87
	/**
88
	 * Verifica se existe existencia de request
89
	 * @return boolean
90
	 */
91
	private function hasRequested() {
92
		if (!$this->instanceResponse) {
93
			throw new NoServiceCall("No request from this service, please call first method request", 1);
94
		}
95
96
		return true;
97
	}
98
99
	/**
100
	 * Retorna o captcha do serviço para o usuário
101
	 * @return string base64_image
102
	 */
103
	public function getCaptcha() {
104
		$this->hasRequested();
105
106
		// Inicia instancia do cURL
107
		$curl = new Curl;
108
109
		// Inicia uma requisição para capturar a imagem do captcha
110
		// informando cookie da requisição passada e os headers
111
		//
112
		// to-do: implementar guzzlehttp?
113
		// ele é melhor que o curl? ou mais organizado?
114
		$curl->init($this->configurations['captcha']);
115
116
		// headers da requisição
117
		$curl->options([
118
			CURLOPT_COOKIEJAR => 'cookiejar',
119
			CURLOPT_HTTPHEADER => array(
120
				"Pragma: no-cache",
121
				"Origin: " . $this->configurations['base'],
122
				"Host: " . array_get($this->configurations, 'headers.Host'),
123
				"User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0",
124
				"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
125
				"Accept-Language: pt-BR,pt;q=0.8,en-US;q=0.5,en;q=0.3",
126
				"Accept-Encoding: gzip, deflate",
127
				"Referer: " . $this->configurations['home'],
128
				"Cookie: flag=1; " . $this->cookie,
129
				"Connection: keep-alive",
130
			),
131
			CURLOPT_RETURNTRANSFER => true,
132
			CURLOPT_FOLLOWLOCATION => 1,
133
			CURLOPT_BINARYTRANSFER => TRUE,
134
			CURLOPT_CONNECTTIMEOUT => 10,
135
			CURLOPT_TIMEOUT => 10,
136
		]);
137
138
		// executa o curl, logo após fechando a conexão
139
		$curl->exec();
140
		$curl->close();
141
142
		// captura do retorno do curl
143
		// o esperado deverá ser o HTML da imagem
144
		$this->captcha = $curl->response();
145
146
		// é uma imagem o retorno?
147
		if (@imagecreatefromstring($this->captcha) == false) {
148
			throw new NoCaptchaResponse('Não foi possível capturar o captcha');
149
		}
150
151
		// constroe o base64 da imagem para o usuário digitar
152
		// to-do: um serviço automatizado para decifrar o captcha?
153
		// talvez deathbycaptcha?
154
		$this->captchaImage = 'data:image/png;base64,' . base64_encode($this->captcha);
155
156
		return $this->captchaImage;
157
	}
158
159
	/**
160
	 * Retorna o cookie da requisição para as
161
	 * próximas requisições
162
	 * @return string $cookie
163
	 */
164
	public function getCookie() {
165
		$this->hasRequested();
166
167
		return $this->cookie;
168
	}
169
170
	/**
171
	 * Alguns serviços possuem outros parametros.
172
	 * Como por exemplo o serviço de SP.
173
	 * No formulário possui o input "parambot"
174
	 * e nas requisições posteriores é preciso enviá-lo.
175
	 *
176
	 * Este método irá buscar no crawler estes parametros avulsos.
177
	 * @return array $params
178
	 */
179
	public function getParams() {
180
		$this->hasRequested();
181
182
		return $this->params;
183
	}
184
185
	/**
186
	 * ServiceInterface from decaptcher
187
	 *
188
	 * Impoe o serviço a ser utilizado para efetuar a quebra do captcha
189
	 * @param  ServiceInterface $decaptcher
190
	 * @return Search
191
	 */
192
	public function decaptcher(ServiceInterface $decaptcher) {
193
		$this->decaptcher = $decaptcher;
194
195
		return $this;
196
	}
197
198
	/**
199
	 * Implement decaptcher
200
	 *
201
	 * @return string
202
	 */
203
	private function resolveCaptcha($captchImageOrtxt) {
204
		// auto decaptcher
205
		if ($this->decaptcher) {
206
			$captchImageOrtxt = $this->decaptcher->upload($captchImageOrtxt);
207
		}
208
209
		return $captchImageOrtxt;
210
	}
211
212
	/**
213
	 * Retorna as informações da empresa/pessoa consultada.
214
	 * @param  integer $document Documento de identificação da entidade
215
	 * @param  string  $cookie   Referencia: $service->cookie()
216
	 * @param  string  $captcha  Texto do captcha resolvido pelo usuário
217
	 * @param  array   $params   Parametros avulsos de requisição. Referência $service->params()
218
	 * @return Crawler   $data     Informações da entidade no serviço.
219
	 */
220
	public function getData($document, $cookie, $captcha, $params, $configurations) {
221
222
		// resolve captcha
223
		$captcha = $this->resolveCaptcha($captcha);
224
225
		// prepara o form
226
		$postParams = [
227
			'origem' => 'comprovante',
228
			'cnpj' => $document, // apenas números
229
			'txtTexto_captcha_serpro_gov_br' => $captcha,
230
			'submit1' => 'Consultar',
231
			'search_type' => 'cnpj',
232
		];
233
234
		$postParams = array_merge($postParams, $params);
235
236
		// inicia o cURL
237
		$curl = new Curl;
238
239
		// vamos registrar qual serviço será consultado
240
		$curl->init($configurations['data']);
241
242
		// define os headers para requisição curl.
243
		$curl->options(
244
			array(
245
				CURLOPT_HTTPHEADER => array(
246
					"Pragma: no-cache",
247
					"Origin: " . $this->configurations['base'],
248
					"Host: " . array_get($configurations, 'headers.Host'),
249
					"User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0",
250
					"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
251
					"Accept-Language: pt-BR,pt;q=0.8,en-US;q=0.5,en;q=0.3",
252
					"Accept-Encoding: gzip, deflate",
253
					"Referer: " . $this->configurations['home'] . '?cnpj=' . $document,
254
					"Cookie: flag=1; " . $cookie,
255
					"Connection: keep-alive",
256
				),
257
				CURLOPT_RETURNTRANSFER => 1,
258
				CURLOPT_BINARYTRANSFER => 1,
259
				CURLOPT_FOLLOWLOCATION => 1,
260
			)
261
		);
262
263
		// efetua a chamada passando os parametros de form
264
		$curl->post($postParams);
265
		$curl->exec();
266
267
		// completa a chamda
268
		$curl->close();
269
270
		// vamos capturar retorno, que deverá ser o HTML para scrapping
271
		$html = $curl->response();
272
273
		if (empty($html)) {
274
			throw new NoServiceResponse('No response from service', 99);
275
		}
276
277
		$crawler = new Crawler($html, array_get($configurations, 'selectors.data'));
278
279
		return $crawler;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $crawler; (zServices\ReceitaFederal...ices\Portais\AN\Crawler) is incompatible with the return type declared by the interface zServices\Miscellany\Int...earchInterface::getData of type array.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
280
	}
281
}