Skip to content

Commit 959d25c

Browse files
committed
Add support to fetch remote files through a Proxy
1 parent 8e6968c commit 959d25c

File tree

1 file changed

+143
-1
lines changed

1 file changed

+143
-1
lines changed

src/phpbrowscap/Browscap.php

Lines changed: 143 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
*
3232
* @package Browscap
3333
* @author Jonathan Stoppani <[email protected]>
34+
* @author Vítor Brandão <[email protected]>
3435
* @copyright Copyright (c) 2006-2012 Jonathan Stoppani
3536
* @version 1.0
3637
* @license http://www.opensource.org/licenses/MIT MIT License
@@ -179,6 +180,28 @@ class Browscap
179180
protected $_patterns = array();
180181
protected $_properties = array();
181182

183+
/**
184+
* An associative array of associative arrays in the format
185+
* `$arr['wrapper']['option'] = $value` passed to stream_context_create()
186+
* when building a stream resource.
187+
*
188+
* Proxy settings are stored in this variable.
189+
*
190+
* @see http://www.php.net/manual/en/function.stream-context-create.php
191+
*
192+
* @var array
193+
*/
194+
protected $_streamContextOptions = array();
195+
196+
/**
197+
* A valid context resource created with stream_context_create().
198+
*
199+
* @see http://www.php.net/manual/en/function.stream-context-create.php
200+
*
201+
* @var resource
202+
*/
203+
protected $_streamContext = null;
204+
182205
/**
183206
* Constructor class, checks for the existence of (and loads) the cache and
184207
* if needed updated the definitions
@@ -308,6 +331,109 @@ public function getBrowser($user_agent = null, $return_array = false)
308331
return $return_array ? $array : (object) $array;
309332
}
310333

334+
/**
335+
* Load (auto-set) proxy settings from environment variables.
336+
*/
337+
public function autodetectProxySettings()
338+
{
339+
$wrappers = array('http', 'https', 'ftp');
340+
341+
foreach ($wrappers as $wrapper) {
342+
$url = getenv($wrapper.'_proxy');
343+
if (!empty($url)) {
344+
$params = array_merge(array(
345+
'port' => null,
346+
'user' => null,
347+
'pass' => null,
348+
), parse_url($url));
349+
$this->addProxySettings($params['host'], $params['port'], $wrapper, $params['user'], $params['pass']);
350+
}
351+
}
352+
}
353+
354+
/**
355+
* Add proxy settings to the stream context array.
356+
*
357+
* @param string $server Proxy server/host
358+
* @param int $port Port
359+
* @param string $wrapper Wrapper: "http", "https", "ftp", others...
360+
* @param string $username Username (when requiring authentication)
361+
* @param string $password Password (when requiring authentication)
362+
*
363+
* @return Browscap
364+
*/
365+
public function addProxySettings($server, $port = 3128, $wrapper = 'http', $username = null, $password = null)
366+
{
367+
$settings = array($wrapper => array(
368+
'proxy' => sprintf('tcp://%s:%d', $server, $port),
369+
'request_fulluri' => true,
370+
));
371+
372+
// Proxy authentication (optional)
373+
if (isset($username) && isset($password)) {
374+
$settings[$wrapper]['header'] = 'Proxy-Authorization: Basic '.base64_encode($username.':'.$password);
375+
}
376+
377+
// Add these new settings to the stream context options array
378+
$this->_streamContextOptions = array_merge(
379+
$this->_streamContextOptions,
380+
$settings
381+
);
382+
383+
/* Return $this so we can chain addProxySettings() calls like this:
384+
* $browscap->
385+
* addProxySettings('http')->
386+
* addProxySettings('https')->
387+
* addProxySettings('ftp');
388+
*/
389+
return $this;
390+
}
391+
392+
/**
393+
* Clear proxy settings from the stream context options array.
394+
*
395+
* @param string $wrapper Remove settings from this wrapper only
396+
*
397+
* @return array Wrappers cleared
398+
*/
399+
public function clearProxySettings($wrapper = null)
400+
{
401+
$wrappers = isset($wrapper) ? array($wrappers) : array_keys($this->_streamContextOptions);
402+
403+
$affectedProtocols = array();
404+
$options = array('proxy', 'request_fulluri', 'header');
405+
foreach ($wrappers as $wrapper) {
406+
407+
// remove wrapper options related to proxy settings
408+
if (isset($this->_streamContextOptions[$wrapper]['proxy'])) {
409+
foreach ($options as $option){
410+
unset($this->_streamContextOptions[$wrapper][$option]);
411+
}
412+
413+
// remove wrapper entry if there are no other options left
414+
if (empty($this->_streamContextOptions[$wrapper])) {
415+
unset($this->_streamContextOptions[$wrapper]);
416+
}
417+
418+
$clearedWrappers[] = $wrapper;
419+
}
420+
}
421+
422+
return $clearedWrappers;
423+
}
424+
425+
/**
426+
* Returns the array of stream context options.
427+
*
428+
* @note Added for debug purposes. Remove at will.
429+
*
430+
* @return array
431+
*/
432+
public function getStreamContextOptions()
433+
{
434+
return $this->_streamContextOptions;
435+
}
436+
311437
/**
312438
* Parses the ini file and updates the cache files
313439
*
@@ -431,6 +557,20 @@ protected function _buildCache()
431557
);
432558
}
433559

560+
/**
561+
* Lazy getter for the stream context resource.
562+
*
563+
* @return resource
564+
*/
565+
protected function _getStreamContext($recreate = false)
566+
{
567+
if (!isset($this->_streamContext) || true === $recreate) {
568+
$this->_streamContext = stream_context_create($this->_streamContextOptions);
569+
}
570+
571+
return $this->_streamContext;
572+
}
573+
434574
/**
435575
* Updates the local copy of the ini file (by version checking) and adapts
436576
* his syntax to the PHP ini parser
@@ -605,7 +745,9 @@ protected function _getRemoteData($url)
605745
throw new Exception('Cannot open the local file');
606746
}
607747
case self::UPDATE_FOPEN:
608-
$file = file_get_contents($url);
748+
// include proxy settings in the file_get_contents() call
749+
$context = $this->_getStreamContext();
750+
$file = file_get_contents($url, false, $context);
609751

610752
if ($file !== false) {
611753
return $file;

0 commit comments

Comments
 (0)