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::hasRequested()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 0
dl 0
loc 7
rs 9.4285
c 0
b 0
f 0
1
<?php namespace zServices\Sintegra\Services\Portais\SP;
2
3
use Captcha\Interfaces\ServiceInterface;
4
use zServices\Miscellany\ClientHttp;
5
use zServices\Miscellany\Curl;
6
use zServices\Miscellany\Exceptions\ImageNotFound;
7
use zServices\Miscellany\Exceptions\NoCaptchaResponse;
8
use zServices\Miscellany\Exceptions\NoServiceCall;
9
use zServices\Miscellany\Exceptions\NoServiceResponse;
10
use zServices\Miscellany\Interfaces\SearchInterface;
11
use zServices\Sintegra\Services\Portais\SP\Crawler;
12
13
/**
14
 *
15
 */
16
class Search implements SearchInterface {
17
	/**
18
	 * Armazena a instãncia atual do request no serviço
19
	 * @var object
20
	 */
21
	private $instanceResponse;
22
23
	/**
24
	 * Armazena o cookie atual
25
	 * @var string
26
	 */
27
	private $cookie;
28
29
	/**
30
	 * Captcha request response
31
	 * @var string
32
	 */
33
	private $captcha;
34
35
	/**
36
	 * Armazena o base64 da imagem do captcha
37
	 * @var string base64
38
	 */
39
	private $captchaImage;
40
41
	/**
42
	 * @var object zServices\Sintegra\Services\ClientHttp
43
	 */
44
	private $client;
45
46
	/**
47
	 * Armazena as configurações para as requisições e crawler
48
	 * @var array
49
	 */
50
	private $configurations;
51
52
	/**
53
	 * [$params description]
54
	 * @var array
55
	 */
56
	private $params = [];
57
58
	/**
59
	 * decaptcher instance
60
	 * @var \Captcha\Interfaces\ServiceInterface
61
	 */
62
	public $decaptcher;
63
64
	/**
65
	 * Antes de chamar o cookie e o captcha, é preciso efetuar uma requisição
66
	 * primária no serviço. Capturando tais informações.
67
	 * Este método deverá fazer essa requisição, armazenando o request
68
	 * para os método como cookie e captcha prepararem suas informações
69
	 *
70
	 * @param  array $configurations  @ref zServices\Sintegra\Services\Sintegra\{Service}\Service::$configurations
71
	 * @return Search
72
	 */
73 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...
74
		$this->configurations = $configurations;
75
76
		// instancia o client http
77
		$this->client = new ClientHttp();
78
79
		// Executa um request para URL do serviço, retornando o cookie da requisição primária
80
		$this->instanceResponse = $this->client->request('GET', $this->configurations['home']);
81
82
		// Captura o cookie da requisição, será usuado posteriormente
83
		$this->cookie = $this->client->cookie();
84
85
		return $this;
86
	}
87
88
	/**
89
	 * Verifica se existe existencia de request
90
	 * @return boolean
91
	 */
92
	private function hasRequested() {
93
		if (!$this->instanceResponse) {
94
			throw new NoServiceCall("No request from this service, please call first method request", 1);
95
		}
96
97
		return true;
98
	}
99
100
	/**
101
	 * Retorna o captcha do serviço para o usuário
102
	 * @return string base64_image
103
	 */
104
	public function getCaptcha() {
105
		$this->hasRequested();
106
107
		$imageSrc = $this->instanceResponse->filter(
108
			array_get($this->configurations, 'selectors.image')
109
		);
110
111
		if (!$imageSrc->count()) {
112
			throw new ImageNotFound("Impossible to crawler image from response", 1);
113
		}
114
115
		$paramBot = $this->instanceResponse->filter(
116
			array_get($this->configurations, 'selectors.paramBot')
117
		);
118
119
		if (!$paramBot->count()) {
120
			throw new ImageNotFound("Impossible to crawler parambot from response", 1);
121
		}
122
123
		// Inicia instancia do cURL
124
		$curl = new Curl;
125
126
		// Inicia uma requisição para capturar a imagem do captcha
127
		// informando cookie da requisição passada e os headers
128
		//
129
		// to-do: implementar guzzlehttp?
130
		// ele é melhor que o curl? ou mais organizado?
131
		$curl->init($this->configurations['base'] . $imageSrc->attr('src'));
132
133
		$this->params['parambot'] = trim($paramBot->attr('value'));
134
135
		// headers da requisição
136
		$curl->options([
137
			CURLOPT_COOKIEJAR => 'cookiejar',
138
			CURLOPT_HTTPHEADER => array(
139
				"Pragma: no-cache",
140
				"Origin: " . $this->configurations['base'],
141
				"Host: " . array_get($this->configurations, 'headers.Host'),
142
				"User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0",
143
				"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
144
				"Accept-Language: pt-BR,pt;q=0.8,en-US;q=0.5,en;q=0.3",
145
				"Accept-Encoding: gzip, deflate",
146
				"Referer: " . $this->configurations['captcha'],
147
				"Cookie: flag=1; " . $this->cookie,
148
				"Connection: keep-alive",
149
			),
150
			CURLOPT_RETURNTRANSFER => true,
151
			CURLOPT_FOLLOWLOCATION => 1,
152
			CURLOPT_BINARYTRANSFER => TRUE,
153
			CURLOPT_CONNECTTIMEOUT => 10,
154
			CURLOPT_TIMEOUT => 10,
155
		]);
156
157
		// executa o curl, logo após fechando a conexão
158
		$curl->exec();
159
		$curl->close();
160
161
		// captura do retorno do curl
162
		// o esperado deverá ser o HTML da imagem
163
		$this->captcha = $curl->response();
164
165
		// é uma imagem o retorno?
166
		if (@imagecreatefromstring($this->captcha) == false) {
167
			throw new NoCaptchaResponse('Não foi possível capturar o captcha');
168
		}
169
170
		// constroe o base64 da imagem para o usuário digitar
171
		// to-do: um serviço automatizado para decifrar o captcha?
172
		// talvez deathbycaptcha?
173
		$this->captchaImage = 'data:image/png;base64,' . base64_encode($this->captcha);
174
175
		return $this->captchaImage;
176
	}
177
178
	/**
179
	 * Retorna o cookie da requisição para as
180
	 * próximas requisições
181
	 * @return string $cookie
182
	 */
183
	public function getCookie() {
184
		$this->hasRequested();
185
186
		return $this->cookie;
187
	}
188
189
	/**
190
	 * Alguns serviços possuem outros parametros.
191
	 * Como por exemplo o serviço de SP.
192
	 * No formulário possui o input "parambot"
193
	 * e nas requisições posteriores é preciso enviá-lo.
194
	 *
195
	 * Este método irá buscar no crawler estes parametros avulsos.
196
	 * @return array $params
197
	 */
198
	public function getParams() {
199
		$this->hasRequested();
200
201
		return $this->params;
202
	}
203
204
	/**
205
	 * ServiceInterface from decaptcher
206
	 *
207
	 * Impoe o serviço a ser utilizado para efetuar a quebra do captcha
208
	 * @param  ServiceInterface $decaptcher
209
	 * @return Search
210
	 */
211
	public function decaptcher(ServiceInterface $decaptcher) {
212
		$this->decaptcher = $decaptcher;
213
214
		return $this;
215
	}
216
217
	/**
218
	 * Implement decaptcher
219
	 *
220
	 * @return string
221
	 */
222
	private function resolveCaptcha($captchImageOrtxt) {
223
		// auto decaptcher
224
		if ($this->decaptcher) {
225
			$captchImageOrtxt = $this->decaptcher->upload($captchImageOrtxt);
226
		}
227
228
		return $captchImageOrtxt;
229
	}
230
231
	/**
232
	 * Retorna as informações da empresa/pessoa consultada.
233
	 * @param  integer $document Documento de identificação da entidade
234
	 * @param  string  $cookie   Referencia: $service->cookie()
235
	 * @param  string  $captcha  Texto do captcha resolvido pelo usuário ou base64
236
	 * @param  array   $params   Parametros avulsos de requisição. Referência $service->params()
237
	 * @return Crawler   $data     Informações da entidade no serviço.
238
	 */
239
	public function getData($document, $cookie, $captcha, $params, $configurations) {
240
241
		// resolve captcha
242
		$captcha = $this->resolveCaptcha($captcha);
243
244
		// prepara o form
245
		$postParams = [
246
			'cnpj' => $document, // apenas números
247
			'Key' => $captcha,
248
			'botao' => 'Consulta por CNPJ',
249
			'hidFlag' => '1',
250
			'ie' => '',
251
			'servico' => 'cnpj',
252
			'paramBot' => $params['parambot'],
253
		];
254
255
		// inicia o cURL
256
		$curl = new Curl;
257
258
		// vamos registrar qual serviço será consultado
259
		$curl->init($configurations['data']);
260
261
		// define os headers para requisição curl.
262
		$curl->options(
263
			array(
264
				CURLOPT_HTTPHEADER => array(
265
					"Origin: http://pfeserv1.fazenda.sp.gov.br",
266
					"Host: pfeserv1.fazenda.sp.gov.br",
267
					"User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/49.0.2623.108 Chrome/49.0.2623.108 Safari/537.36",
268
					"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
269
					"Accept-Language: pt-BR,pt;q=0.8,en-US;q=0.6,en;q=0.4,es;q=0.2",
270
					"Accept-Encoding: gzip, deflate",
271
					"Referer: http://pfeserv1.fazenda.sp.gov.br/sintegrapfe/consultaSintegraServlet",
272
					"Cookie: flag=1; " . $cookie,
273
					"Connection: keep-alive",
274
				),
275
				CURLOPT_RETURNTRANSFER => 1,
276
				CURLOPT_BINARYTRANSFER => 1,
277
				CURLOPT_FOLLOWLOCATION => 1,
278
			)
279
		);
280
281
		// efetua a chamada passando os parametros de form
282
		$curl->post($postParams);
283
		$curl->exec();
284
285
		// completa a chamda
286
		$curl->close();
287
288
		// vamos capturar retorno, que deverá ser o HTML para scrapping
289
		$html = $curl->response();
290
291
		if (empty($html)) {
292
			throw new NoServiceResponse('No response from service', 99);
293
		}
294
295
		$crawler = new Crawler($html, array_get($configurations, 'selectors.data'));
296
297
		return $crawler;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $crawler; (zServices\Sintegra\Services\Portais\SP\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...
298
	}
299
}