Issues (994)

src/Extender/request.php (5 issues)

1
<?php
2
3
namespace Extender;
4
5
use Curl\Curl;
6
use Filemanager\file;
7
use JSON\json;
8
use MVC\Exception;
9
use MVC\helper;
10
11
class request extends Curl
12
{
13
  private $result_request = [];
14
  /**
15
   * request instances.
16
   *
17
   * @var request
18
   */
19
  private static $_instance = null;
20
21
  public function __construct($base = null)
22
  {
23
    parent::__construct($base);
24
  }
25
26
  public function disableSSL()
27
  {
28
    $this->setOpt(CURLOPT_SSL_VERIFYPEER, false);
29
    $this->setOpt(CURLOPT_SSL_VERIFYHOST, false);
30
31
    return $this;
32
  }
33
34
  public $cache = false;
35
36
  /**
37
   * Execute curl.
38
   *
39
   * @return string|array|null
40
   */
41
  public function execute(string $method, string $path, bool $rewrite = false)
42
  {
43
    $self = $this;
44
    $self->set_method($method);
45
    $self->set_url($path);
46
    if ($self->cache) {
47
      if (!$rewrite) {
48
        if (file_exists($self->cache_path())) {
49
          $this->response = $self->get_cache();
50
        }
51
      }
52
    }
53
54
    if (!$this->response || empty($this->response)) {
55
      $this->exec();
56
    } else {
57
      $this->error = false;
58
    }
59
60
    if (!$this->error) {
61
      if ($this->cache) {
62
        \Filemanager\file::file($this->cache_path(), $this->response, true);
63
      }
64
      if (is_object($this->response)) {
65
        $this->response = (array) $this->response;
66
      }
67
68
      return $this->response;
69
    }
70
71
    return null;
72
  }
73
74
  /**
75
   * Get Cache Path.
76
   *
77
   * @return string
78
   */
79
  private function cache_path()
80
  {
81
    return ROOT . '/tmp/curl/' . md5($this->url);
82
  }
83
84
  /**
85
   * Get cached content.
86
   *
87
   * @return string|array|null
88
   */
89
  private function get_cache()
90
  {
91
    if (file_exists($this->cache_path())) {
92
      return \Filemanager\file::get($this->cache_path(), true);
93
    }
94
  }
95
96
  public function set_url(string $url)
97
  {
98
    $this->setUrl($url);
99
100
    return $this;
101
  }
102
103
  public function set_method(string $method)
104
  {
105
    $this->setOpt(CURLOPT_CUSTOMREQUEST, strtoupper($method));
106
107
    return $this;
108
  }
109
110
  public static function getInstance($base = null)
111
  {
112
    if (null === self::$_instance) {
113
      self::$_instance = new self($base);
114
    }
115
116
    return self::$_instance;
117
  }
118
119
  public static function static_request($opt)
120
  {
121
    return self::getInstance()->request($opt);
122
    //return self::request($opt);
123
  }
124
125
  private $require_content_length = false;
126
  private $dumpNow = false;
127
128
  public function isDUMPNow()
129
  {
130
    return true === $this->dumpNow;
131
  }
132
133
  public function DUMPNow(...$what)
134
  {
135
    if ($this->isDUMPNow()) {
136
      $this->exitJSON($what);
137
    }
138
  }
139
140
  public function exitJSON(...$what)
141
  {
142
    foreach ($what as $these) {
143
      json::json($these);
144
      echo "\n\n";
145
    }
146
    exit;
0 ignored issues
show
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
147
  }
148
149
  /**
150
   * cURL shooter request.
151
   *
152
   * @param array $opt
153
   *
154
   * @return array
155
   */
156
  public function request($opt)
157
  {
158
    if (!isset($opt['url'])) {
159
      throw new Exception('URL needed', 1);
160
    }
161
    $msisdn = isset($_SESSION['telkomsel']['msisdn']) ? $_SESSION['telkomsel']['msisdn'] : 'default';
162
    //$verbose = __DIR__ . '/otp/http/' . $msisdn . '.' . substr(clean_string(urldecode(urldecode($opt['url']))), 0, 50) . '.txt';
163
    //file_put_contents($verbose, '');
164
    //$curl_log = fopen($verbose, 'a');
165
    $ch = curl_init();
166
167
    $result = ['request' => [], 'response' => []];
168
    if (isset($opt['postdata'])) {
169
      if (is_array($opt['postdata'])) {
170
        $opt['postdata'] = http_build_query($opt['postdata'], '', '&');
171
      }
172
      curl_setopt($ch, CURLOPT_POSTFIELDS, $opt['postdata']);
173
      $result['request']['postdata'] = $opt['postdata'];
174
      $this->require_content_length = true;
175
    }
176
    if (isset($opt['headers']) && is_array($opt['headers'])) {
177
      $headers = $opt['headers'];
178
      if (isset($opt['headers_trim'])) {
179
        $headers = array_map('trim', $headers);
180
        $headers = array_filter($headers);
181
        $headers = array_values($headers);
182
      }
183
      for ($i = 0; $i < count($headers); ++$i) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
184
        $header = array_map('trim', explode(':', $headers[$i]));
185
        $small_header = strtolower($header[0]);
186
        if ('content-length' == $small_header && true === $this->require_content_length) {
187
          $headers[$i] = $header[0] . ': ' . strlen($opt['postdata']);
188
        }
189
        if ('user-agent' == $small_header) {
190
          curl_setopt($ch, CURLOPT_USERAGENT, $header[1]);
191
        }
192
      }
193
      //$this->DUMPNow($headers, $opt);
194
195
      curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
196
      $result['request']['headers'] = $headers;
197
    }
198
    curl_setopt($ch, CURLOPT_URL, trim($opt['url']));
199
    $result['url'] = $opt['url'];
200
    if (isset($opt['post']) && $opt['post']) {
201
      curl_setopt($ch, CURLOPT_POST, 1);
202
    }
203
204
    //evj($_SESSION, isset($opt['cookie']) && true === $opt['cookie'] && isset($_SESSION['cookie']));
205
    if (isset($opt['cookie']) && true === $opt['cookie'] && isset($_SESSION['cookie'])) {
206
      $cookie = isset($_SESSION['cookie']) ? $_SESSION['cookie'] : null;
207
      if (is_string($opt['cookie']) && !empty($opt['cookie'])) {
208
        $cookie = $opt['cookie'];
209
      }
210
211
      if ($cookie = file::file($cookie, '')) {
0 ignored issues
show
'' of type string is incompatible with the type boolean expected by parameter $create of Filemanager\file::file(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

211
      if ($cookie = file::file($cookie, /** @scrutinizer ignore-type */ '')) {
Loading history...
212
        if (!file_exists($cookie)) {
213
          throw new Exception("$cookie not exists", 1);
214
          //file_put_contents($cookie, '');
215
        }
216
        curl_setopt($ch, CURLOPT_COOKIEJAR, realpath($cookie));
217
        curl_setopt($ch, CURLOPT_COOKIEFILE, realpath($cookie));
218
        $result['request']['cookie-file'] = realpath($cookie);
219
        $result['response']['cookie-file'] = realpath($cookie);
220
      }
221
    }
222
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 0);
223
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
224
    curl_setopt($ch, CURLOPT_HEADER, true);
225
    //curl_setopt($ch, CURLOPT_VERBOSE, true);
226
    //curl_setopt($ch, CURLOPT_STDERR, $curl_log);
227
    curl_setopt($ch, CURLINFO_HEADER_OUT, true);
228
    //curl_setopt($ch, CURLOPT_ENCODING, '');
229
    if (isset($opt['setopt']) && is_array($opt['setopt']) && !empty($opt['setopt'])) {
230
      foreach ($opt['setopt'] as $key => $value) {
231
        curl_setopt($ch, $key, $value);
232
      }
233
    }
234
235
    if (isset($opt['proxy'])) {
236
      curl_setopt($ch, CURLOPT_PROXY, $opt['proxy']);
237
      curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, 1);
238
      if (isset($opt['proxy_type'])) {
239
        switch ($opt['proxy_type']) {
240
          case 'socks5':
241
            curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
242
            break;
243
          case 'http':
244
            curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
245
            break;
246
          case 'https':
247
            curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_HTTPS);
248
            break;
249
          case 'socks4':
250
            curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4);
251
            break;
252
        }
253
      }
254
    }
255
256
    $data = curl_exec($ch);
257
    if (!is_string($data) && $data) {
258
      $data = json::assoc($data);
0 ignored issues
show
$data of type true is incompatible with the type array|object expected by parameter $arr of JSON\json::assoc(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

258
      $data = json::assoc(/** @scrutinizer ignore-type */ $data);
Loading history...
259
    }
260
    $result['curl_exec'] = $data;
261
    // save to log
262
    $parse_url = helper::parse_url2($opt['url']);
263
    $filesave = "{$parse_url['host']}/{$parse_url['path']}";
264
    $filepath = helper::platformSlashes(__DIR__ . "/log/curl_exec/$msisdn/$filesave");
265
    if (!is_dir(dirname($filepath))) {
266
      mkdir(dirname($filepath), 0777, true);
267
    }
268
    file::file($filepath, $data, true);
269
    //rewind($curl_log);
270
    $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
271
    $headerSent = curl_getinfo($ch, CURLINFO_HEADER_OUT);
272
    $headerSent = explode("\n", $headerSent);
273
    $headerSent = array_map(function ($v) {
274
      return preg_replace("/\r$/m", '', $v);
275
    }, $headerSent);
276
    $result['request']['raw'] = $headerSent;
277
    $header = substr($data, 0, $header_size);
278
    $body = substr($data, $header_size);
279
    if (json::is_json($body)) {
280
      $body = json_decode($body, true);
281
    }
282
283
    $header = explode("\n", $header);
284
    $header = array_map(function ($v) {
285
      return preg_replace("/\r$/m", '', $v);
286
    }, $header);
287
288
    $result['response']['headers'] = $header;
289
    foreach ($header as $h) {
290
      $ex = explode(':', $h);
291
      if (isset($ex[0]) && isset($ex[1])) {
292
        $hkey = $ex[0];
293
        //var_dump($hkey, strpos(strtolower(trim($hkey)), 'oauth'));
294
        if (false !== strpos(strtolower($hkey), 'oauth')) {
295
          $_SESSION['im3'][$opt['url']]['oauth'] = trim($ex[1]);
296
          $_SESSION['im3']['oauth'] = trim($ex[1]);
297
        }
298
      }
299
    }
300
    if (is_iterable($body)) {
301
      foreach ($body as $key => $value) {
302
        $_SESSION['im3'][$key] = $value;
303
      }
304
      if (isset($body['data']['tokenid'])) {
305
        $_SESSION['im3']['tokenid'] = $body['data']['tokenid'];
306
      }
307
    }
308
    $result['response']['body'] = $body;
309
    $result['options'] = $opt;
310
    if (isset($opt['verbose'])) {
311
      $_SESSION['verbose'][$opt['url']] = $result;
312
    }
313
    //exit(gettype($ch));
314
    curl_close($ch);
315
316
    return $result;
317
  }
318
319
  public static function getCurlOpt($ch, int $what)
320
  {
321
    return curl_getinfo($ch, $what);
322
  }
323
324
  public function set_header_array($headers, $trim = false)
325
  {
326
    if (!is_array($headers)) {
327
      throw new \MVC\Exception('Header must array formatted', 1);
328
    }
329
    if ($trim) {
330
      $headers = array_map('trim', $headers);
331
    }
332
    $this->setOpt(CURLOPT_HTTPHEADER, $headers);
333
    $this->result_request['request']['headers'] = $headers;
334
335
    return $this;
336
  }
337
338
  public function set_cookie_file($cookie = null)
339
  {
340
    if (!$cookie) {
341
      $cookie = __DIR__ . '/cookie/default.txt';
342
      if (isset($_SERVER['HTTP_USER_AGENT'])) {
343
        $cookie = __DIR__ . '/cookie/' . $_SERVER['HTTP_USER_AGENT'] . '.txt';
344
      }
345
    }
346
    if ($cookie) {
347
      \Filemanager\file::file($cookie, '#cookie');
0 ignored issues
show
'#cookie' of type string is incompatible with the type boolean expected by parameter $create of Filemanager\file::file(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

347
      \Filemanager\file::file($cookie, /** @scrutinizer ignore-type */ '#cookie');
Loading history...
348
    }
349
    $this->setCookieFile($cookie);
350
    $this->setCookieJar($cookie);
351
    $this->result_request['cookie'] = $cookie;
352
353
    return $this;
354
  }
355
356
  /**
357
   * Check array is assoc
358
   * * var_dump(isAssoc(['a', 'b', 'c'])); // false
359
   * * var_dump(isAssoc(["0" => 'a', "1" => 'b', "2" => 'c'])); // false
360
   * * var_dump(isAssoc(["1" => 'a', "0" => 'b', "2" => 'c'])); // true
361
   * * var_dump(isAssoc(["a" => 'a', "b" => 'b', "c" => 'c'])); // true.
362
   *
363
   * @return bool
364
   */
365
  public function isAssoc(array $arr)
366
  {
367
    if ([] === $arr) {
368
      return false;
369
    }
370
371
    return array_keys($arr) !== range(0, count($arr) - 1);
372
  }
373
374
  /**
375
   * Check array has some string key.
376
   *
377
   * @return bool
378
   */
379
  public function has_string_keys(array $array)
380
  {
381
    return count(array_filter(array_keys($array), 'is_string')) > 0;
382
  }
383
}
384
385
if (!function_exists('is_iterable')) {
386
  function is_iterable($var)
387
  {
388
    return is_array($var) || $var instanceof \Traversable;
389
  }
390
}
391