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.
Completed
Push — master ( a219be...88f57d )
by Carlos
03:30
created

Search::decaptcher()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 3
nc 1
nop 1
dl 0
loc 5
rs 9.4285
c 1
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
	 * Antes de chamar o cookie e o captcha, é preciso efetuar uma requisição
59
	 * primária no serviço. Capturando tais informações.
60
	 * Este método deverá fazer essa requisição, armazenando o request
61
	 * para os método como cookie e captcha prepararem suas informações
62
	 *
63
	 * @param  array $configurations  @ref zServices\Sintegra\Services\Sintegra\{Service}\Service::$configurations
64
	 * @return Search
65
	 */
66 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...
67
		$this->configurations = $configurations;
68
69
		// instancia o client http
70
		$this->client = new ClientHttp();
71
72
		// Executa um request para URL do serviço, retornando o cookie da requisição primária
73
		$this->instanceResponse = $this->client->request('GET', $this->configurations['home']);
74
75
		// Captura o cookie da requisição, será usuado posteriormente
76
		$this->cookie = $this->client->cookie();
77
78
		return $this;
79
	}
80
81
	/**
82
	 * Verifica se existe existencia de request
83
	 * @return boolean
84
	 */
85
	private function hasRequested() {
86
		if (!$this->instanceResponse) {
87
			throw new NoServiceCall("No request from this service, please call first method request", 1);
88
		}
89
90
		return true;
91
	}
92
93
	/**
94
	 * Retorna o captcha do serviço para o usuário
95
	 * @return string base64_image
96
	 */
97
	public function getCaptcha() {
98
		$this->hasRequested();
99
100
		// Inicia instancia do cURL
101
		$curl = new Curl;
102
103
		// Inicia uma requisição para capturar a imagem do captcha
104
		// informando cookie da requisição passada e os headers
105
		//
106
		// to-do: implementar guzzlehttp?
107
		// ele é melhor que o curl? ou mais organizado?
108
		$curl->init($this->configurations['captcha']);
109
110
		// headers da requisição
111
		$curl->options([
112
			CURLOPT_COOKIEJAR => 'cookiejar',
113
			CURLOPT_HTTPHEADER => array(
114
				"Pragma: no-cache",
115
				"Origin: " . $this->configurations['base'],
116
				"Host: " . array_get($this->configurations, 'headers.Host'),
117
				"User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0",
118
				"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
119
				"Accept-Language: pt-BR,pt;q=0.8,en-US;q=0.5,en;q=0.3",
120
				"Accept-Encoding: gzip, deflate",
121
				"Referer: " . $this->configurations['home'],
122
				"Cookie: flag=1; " . $this->cookie,
123
				"Connection: keep-alive",
124
			),
125
			CURLOPT_RETURNTRANSFER => true,
126
			CURLOPT_FOLLOWLOCATION => 1,
127
			CURLOPT_BINARYTRANSFER => TRUE,
128
			CURLOPT_CONNECTTIMEOUT => 10,
129
			CURLOPT_TIMEOUT => 10,
130
		]);
131
132
		// executa o curl, logo após fechando a conexão
133
		$curl->exec();
134
		$curl->close();
135
136
		// captura do retorno do curl
137
		// o esperado deverá ser o HTML da imagem
138
		$this->captcha = $curl->response();
139
140
		// é uma imagem o retorno?
141
		if (@imagecreatefromstring($this->captcha) == false) {
142
			throw new NoCaptchaResponse('Não foi possível capturar o captcha');
143
		}
144
145
		// constroe o base64 da imagem para o usuário digitar
146
		// to-do: um serviço automatizado para decifrar o captcha?
147
		// talvez deathbycaptcha?
148
		$this->captchaImage = 'data:image/png;base64,' . base64_encode($this->captcha);
149
150
		return $this->captchaImage;
151
	}
152
153
	/**
154
	 * Retorna o cookie da requisição para as
155
	 * próximas requisições
156
	 * @return string $cookie
157
	 */
158
	public function getCookie() {
159
		$this->hasRequested();
160
161
		return $this->cookie;
162
	}
163
164
	/**
165
	 * Alguns serviços possuem outros parametros.
166
	 * Como por exemplo o serviço de SP.
167
	 * No formulário possui o input "parambot"
168
	 * e nas requisições posteriores é preciso enviá-lo.
169
	 *
170
	 * Este método irá buscar no crawler estes parametros avulsos.
171
	 * @return array $params
172
	 */
173
	public function getParams() {
174
		$this->hasRequested();
175
176
		return $this->params;
177
	}
178
179
	/**
180
	 * ServiceInterface from decaptcher
181
	 *
182
	 * Impoe o serviço a ser utilizado para efetuar a quebra do captcha
183
	 * @param  ServiceInterface $decaptcher
184
	 * @return Search
185
	 */
186
	public function decaptcher(ServiceInterface $decaptcher) {
187
		$this->decaptcher = $decaptcher;
0 ignored issues
show
Bug introduced by
The property decaptcher does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
188
189
		return $this;
190
	}
191
192
	/**
193
	 * Implement decaptcher
194
	 *
195
	 * @return string
196
	 */
197
	private function resolveCaptcha($captchImageOrtxt) {
198
		// auto decaptcher
199
		if ($this->decaptcher) {
200
			$captchImageOrtxt = $this->decaptcher->upload($captchImageOrtxt);
201
		}
202
203
		return $captchImageOrtxt;
204
	}
205
206
	/**
207
	 * Retorna as informações da empresa/pessoa consultada.
208
	 * @param  integer $document Documento de identificação da entidade
209
	 * @param  string  $cookie   Referencia: $service->cookie()
210
	 * @param  string  $captcha  Texto do captcha resolvido pelo usuário
211
	 * @param  array   $params   Parametros avulsos de requisição. Referência $service->params()
212
	 * @return Crawler   $data     Informações da entidade no serviço.
213
	 */
214
	public function getData($document, $cookie, $captcha, $params, $configurations) {
215
216
		// resolve captcha
217
		$captcha = $this->resolveCaptcha($captcha);
218
219
		// prepara o form
220
		$postParams = [
221
			'origem' => 'comprovante',
222
			'cnpj' => $document, // apenas números
223
			'txtTexto_captcha_serpro_gov_br' => $captcha,
224
			'submit1' => 'Consultar',
225
			'search_type' => 'cnpj',
226
		];
227
228
		$postParams = array_merge($postParams, $params);
229
230
		// inicia o cURL
231
		$curl = new Curl;
232
233
		// vamos registrar qual serviço será consultado
234
		$curl->init($configurations['data']);
235
236
		// define os headers para requisição curl.
237
		$curl->options(
238
			array(
239
				CURLOPT_HTTPHEADER => array(
240
					"Pragma: no-cache",
241
					"Origin: " . $this->configurations['base'],
242
					"Host: " . array_get($configurations, 'headers.Host'),
243
					"User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0",
244
					"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
245
					"Accept-Language: pt-BR,pt;q=0.8,en-US;q=0.5,en;q=0.3",
246
					"Accept-Encoding: gzip, deflate",
247
					"Referer: " . $this->configurations['home'] . '?cnpj=' . $document,
248
					"Cookie: flag=1; " . $cookie,
249
					"Connection: keep-alive",
250
				),
251
				CURLOPT_RETURNTRANSFER => 1,
252
				CURLOPT_BINARYTRANSFER => 1,
253
				CURLOPT_FOLLOWLOCATION => 1,
254
			)
255
		);
256
257
		// efetua a chamada passando os parametros de form
258
		$curl->post($postParams);
259
		$curl->exec();
260
261
		// completa a chamda
262
		$curl->close();
263
264
		// vamos capturar retorno, que deverá ser o HTML para scrapping
265
		$html = $curl->response();
266
267
		if (empty($html)) {
268
			throw new NoServiceResponse('No response from service', 99);
269
		}
270
271
		$crawler = new Crawler($html, array_get($configurations, 'selectors.data'));
272
273
		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...
274
	}
275
}