Skip to content

Commit 6232d52

Browse files
committed
php-proxy 5.1
1 parent b104ec0 commit 6232d52

File tree

6 files changed

+87
-65
lines changed

6 files changed

+87
-65
lines changed

composer.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22
"name": "athlon1600/php-proxy",
33
"type": "library",
44
"keywords": ["php proxy", "proxy script", "php web proxy", "web proxy", "php proxy script"],
5+
"license": "MIT",
56
"homepage": "https://www.php-proxy.com/",
67
"require": {
78
"ext-curl": "*",
8-
"symfony/event-dispatcher": "~3.2"
99
},
1010
"suggest": {
1111
"predis/predis": "For caching purposes"

src/Event/ProxyEvent.php

+1-5
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,7 @@
22

33
namespace Proxy\Event;
44

5-
use Symfony\Component\EventDispatcher\Event;
6-
7-
// http://symfony.com/doc/current/components/event_dispatcher/generic_event.html
8-
class ProxyEvent extends Event implements \ArrayAccess {
9-
5+
class ProxyEvent implements \ArrayAccess {
106
private $data;
117

128
public function __construct($data = array()){

src/Plugin/AbstractPlugin.php

+25-24
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,10 @@
22

33
namespace Proxy\Plugin;
44

5-
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
6-
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
75
use Proxy\Event\ProxyEvent;
86

9-
abstract class AbstractPlugin implements EventSubscriberInterface {
10-
7+
abstract class AbstractPlugin {
8+
119
// apply these methods only to those events whose request URL passes this filter
1210
protected $url_pattern;
1311

@@ -27,26 +25,40 @@ public function onCompleted(ProxyEvent $event){
2725
// fired after the full response=headers+body has been read - will only be called on "non-streaming" responses
2826
}
2927

30-
// dispatch based on filter
31-
final public function route(ProxyEvent $event, $event_name, EventDispatcherInterface $dispatcher){
28+
final public function subscribe($dispatcher){
29+
30+
$dispatcher->addListener('request.before_send', function($event){
31+
$this->route('request.before_send', $event);
32+
});
33+
34+
$dispatcher->addListener('request.sent', function($event){
35+
$this->route('request.sent', $event);
36+
});
37+
38+
$dispatcher->addListener('curl.callback.write', function($event){
39+
$this->route('curl.callback.write', $event);
40+
});
41+
42+
$dispatcher->addListener('request.complete', function($event){
43+
$this->route('request.complete', $event);
44+
});
45+
}
3246

47+
// dispatch based on filter
48+
final private function route($event_name, ProxyEvent $event){
3349
$url = $event['request']->getUri();
3450

3551
// url filter provided and current request url does not match it
3652
if($this->url_pattern){
37-
if(strpos($this->url_pattern, '/') === 0){
38-
if(!preg_match($this->url_pattern, $url))
53+
if(starts_with($this->url_pattern, '/') && preg_match($this->url_pattern, $url) !== 1){
3954
return;
40-
}
41-
else
42-
{
43-
if(stripos($url, $this->url_pattern) === false)
55+
} else if(stripos($url, $this->url_pattern) === false){
4456
return;
4557
}
4658
}
4759

4860
switch($event_name){
49-
61+
5062
case 'request.before_send':
5163
$this->onBeforeRequest($event);
5264
break;
@@ -64,17 +76,6 @@ final public function route(ProxyEvent $event, $event_name, EventDispatcherInter
6476
break;
6577
}
6678
}
67-
68-
// This method returns an array indexed by event names and whose values are either the method name to call
69-
// or an array composed of the method name to call and a priority.
70-
final public static function getSubscribedEvents(){
71-
return array(
72-
'request.before_send' => 'route',
73-
'request.sent' => 'route',
74-
'curl.callback.write' => 'route',
75-
'request.complete' => 'route'
76-
);
77-
}
7879
}
7980

8081
?>

src/Plugin/ProxifyPlugin.php

+13-15
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,9 @@ class ProxifyPlugin extends AbstractPlugin {
1212
private $base_url = '';
1313

1414
private function css_url($matches){
15-
16-
$url = trim($matches[1]);
1715

18-
if(stripos($url, 'data:') === 0){
16+
$url = trim($matches[1]);
17+
if(starts_with($url, 'data:')){
1918
return $matches[0];
2019
}
2120

@@ -33,7 +32,8 @@ private function html_attr($matches){
3332
// could be empty?
3433
$url = trim($matches[2]);
3534

36-
if(stripos($url, 'data:') === 0 || stripos($url, 'magnet:') === 0 || stripos($url, 'about:') === 0 || stripos($url, 'javascript:') === 0 || stripos($url, 'mailto:') === 0 || stripos($url, 'tel:') === 0 || stripos($url, 'ios-app:') === 0 || stripos($url, 'android-app:') === 0){
35+
$schemes = array('data:', 'magnet:', 'about:', 'javascript:', 'mailto:', 'tel:', 'ios-app:', 'android-app:');
36+
if(starts_with($url, $schemes)){
3737
return $matches[0];
3838
}
3939

@@ -101,7 +101,7 @@ private function meta_refresh($matches){
101101

102102
// <title>, <base>, <link>, <style>, <meta>, <script>, <noscript>
103103
private function proxify_head($str){
104-
104+
105105
// let's replace page titles with something custom
106106
if(Config::get('replace_title')){
107107
$str = preg_replace('/<title[^>]*>(.*?)<\/title>/is', '<title>'.Config::get('replace_title').'</title>', $str);
@@ -137,29 +137,27 @@ private function proxify_css($str){
137137
}
138138

139139
public function onCompleted(ProxyEvent $event){
140-
140+
141141
// to be used when proxifying all the relative links
142142
$this->base_url = $event['request']->getUri();
143+
$url_host = parse_url($this->base_url, PHP_URL_HOST);
143144

144145
$response = $event['response'];
145146
$content_type = $response->headers->get('content-type');
146147

147148
$str = $response->getContent();
148149

149150
// DO NOT do any proxification on .js files and text/plain content type
150-
if($content_type == 'text/javascript' || $content_type == 'application/javascript' || $content_type == 'application/x-javascript' || $content_type == 'text/plain'){
151+
$no_proxify = array('text/javascript', 'application/javascript', 'application/x-javascript', 'text/plain');
152+
if(in_array($content_type, $no_proxify)){
151153
return;
152154
}
153155

154156
// remove JS from urls
155-
$js_remove = Config::get('js_remove');
156-
if(is_array($js_remove)){
157-
$domain = parse_url($this->base_url, PHP_URL_HOST);
158-
159-
foreach($js_remove as $pattern){
160-
if(strpos($domain, $pattern) !== false){
161-
$str = Html::remove_scripts($str);
162-
}
157+
$js_remove = (array)Config::get('js_remove');
158+
foreach($js_remove as $pattern){
159+
if(strpos($url_host, $pattern) !== false){
160+
$str = Html::remove_scripts($str);
163161
}
164162
}
165163

src/Proxy.php

+43-20
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,15 @@
22

33
namespace Proxy;
44

5-
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
6-
use Symfony\Component\EventDispatcher\EventDispatcher;
7-
use Symfony\Component\EventDispatcher\Event;
8-
use Symfony\Component\EventDispatcher\GenericEvent;
9-
10-
use Proxy\Config;
115
use Proxy\Event\ProxyEvent;
126
use Proxy\Http\Request;
137
use Proxy\Http\Response;
8+
use Proxy\Config;
149

1510
class Proxy {
16-
17-
// proxy version!
18-
const VERSION = '5.0.1';
11+
12+
// Proxy script version
13+
const VERSION = '5.1.0';
1914

2015
private $dispatcher;
2116

@@ -28,15 +23,14 @@ class Proxy {
2823
private $status_found = false;
2924

3025
public function __construct(){
31-
$this->dispatcher = new EventDispatcher();
26+
// do nothing for now
3227
}
3328

3429
public function setOutputBuffering($output_buffering){
3530
$this->output_buffering = $output_buffering;
3631
}
3732

3833
private function header_callback($ch, $headers){
39-
4034
$parts = explode(":", $headers, 2);
4135

4236
// extract status code
@@ -60,7 +54,7 @@ private function header_callback($ch, $headers){
6054
$event = new ProxyEvent(array('request' => $this->request, 'response' => $this->response, 'proxy' => &$this));
6155

6256
// this is the end of headers - last line is always empty - notify the dispatcher about this
63-
$this->dispatcher->dispatch('request.sent', $event);
57+
$this->dispatch('request.sent', $event);
6458
}
6559

6660
return strlen($headers);
@@ -70,7 +64,7 @@ private function write_callback($ch, $str){
7064

7165
$len = strlen($str);
7266

73-
$this->dispatcher->dispatch('curl.callback.write', new ProxyEvent(array(
67+
$this->dispatch('curl.callback.write', new ProxyEvent(array(
7468
'request' => $this->request,
7569
'data' => $str
7670
)));
@@ -83,8 +77,34 @@ private function write_callback($ch, $str){
8377
return $len;
8478
}
8579

86-
public function getEventDispatcher(){
87-
return $this->dispatcher;
80+
// TODO: move this all into its own Dispatcher class?
81+
// https://github.com/guzzle/guzzle/blob/5.3/src/Event/Emitter.php
82+
// https://github.com/laravel/framework/blob/5.0/src/Illuminate/Events/Dispatcher.php#L72
83+
private $listeners = array();
84+
85+
public function addListener($event, $callback, $priority = 0){
86+
$this->listeners[$event][$priority][] = $callback;
87+
}
88+
89+
public function addSubscriber($subscriber){
90+
if(method_exists($subscriber, 'subscribe')){
91+
$subscriber->subscribe($this);
92+
}
93+
}
94+
95+
private function dispatch($event_name, $event){
96+
97+
if(isset($this->listeners[$event_name])){
98+
$temp = (array)$this->listeners[$event_name];
99+
100+
foreach($temp as $priority => $listeners){
101+
foreach( (array)$listeners as $listener){
102+
if(is_callable($listener) ){
103+
$listener($event);
104+
}
105+
}
106+
}
107+
}
88108
}
89109

90110
public function forward(Request $request, $url){
@@ -122,11 +142,13 @@ public function forward(Request $request, $url){
122142
$options[CURLOPT_WRITEFUNCTION] = array($this, 'write_callback');
123143

124144
// Notify any listeners that the request is ready to be sent, and this is your last chance to make any modifications.
125-
$this->dispatcher->dispatch('request.before_send', new ProxyEvent(array('request' => $this->request, 'response' => $this->response)));
145+
$this->dispatch('request.before_send', new ProxyEvent(array(
146+
'request' => $this->request,
147+
'response' => $this->response
148+
)));
126149

127150
// We may not even need to send this request if response is already available somewhere (CachePlugin)
128151
if($this->request->params->has('request.complete')){
129-
130152
// do nothing?
131153
} else {
132154

@@ -146,9 +168,7 @@ public function forward(Request $request, $url){
146168

147169
// there must have been an error if at this point
148170
if(!$result){
149-
150171
$error = sprintf('(%d) %s', curl_errno($ch), curl_error($ch));
151-
152172
throw new \Exception($error);
153173
}
154174

@@ -159,7 +179,10 @@ public function forward(Request $request, $url){
159179
$this->output_buffer = null;
160180
}
161181

162-
$this->dispatcher->dispatch('request.complete', new ProxyEvent(array('request' => $this->request, 'response' => $this->response)));
182+
$this->dispatch('request.complete', new ProxyEvent(array(
183+
'request' => $this->request,
184+
'response' => $this->response
185+
)));
163186

164187
return $this->response;
165188
}

src/helpers.php

+4
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ function starts_with($haystack, $needles){
1717
return false;
1818
}
1919

20+
function str_before($subject, $search){
21+
return $search === '' ? $subject : explode($search, $subject)[0];
22+
}
23+
2024

2125
function is_html($content_type){
2226
return clean_content_type($content_type) == 'text/html';

0 commit comments

Comments
 (0)