Skip to content

Instantly share code, notes, and snippets.

@joyqi
Created February 6, 2020 04:16
Show Gist options
  • Save joyqi/7f153b1a998ca5cde8ae92486eb46197 to your computer and use it in GitHub Desktop.
Save joyqi/7f153b1a998ca5cde8ae92486eb46197 to your computer and use it in GitHub Desktop.
用PHP写的简单AJAX跨域代理
<?php
define('REFERER', 'joyqi.github.io');
define('REDIS_CACHE', '127.0.0.1:6379');
define('TIMEOUT', 5);
function check_host($host) {
if ('localhost' == $host) {
return false;
}
$address = gethostbyname($host);
$inet = inet_pton($address);
if (false === $inet) {
// 有可能是ipv6的地址
$records = dns_get_record($host, DNS_AAAA);
if (empty($records)) {
$status = 200;
return false;
}
$address = $records[0]['ipv6'];
$inet = inet_pton($address);
}
if (strpos($address, '.')) {
// ipv4
// 非公网地址
$privateNetworks = array(
'10.0.0.0|10.255.255.255',
'172.16.0.0|172.31.255.255',
'192.168.0.0|192.168.255.255',
'169.254.0.0|169.254.255.255',
'127.0.0.0|127.255.255.255'
);
$long = ip2long($address);
foreach ($privateNetworks as $network) {
list ($from, $to) = explode('|', $network);
if ($long >= ip2long($from) && $long <= ip2long($to)) {
return false;
}
}
} else {
// ipv6
// https://en.wikipedia.org/wiki/Private_network
$from = inet_pton('fd00::');
$to = inet_pton('fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff');
if ($inet >= $from && $inet <= $to) {
return false;
}
}
return true;
}
function request($url, &$status = 500) {
if (defined('REDIS_CACHE') && REDIS_CACHE) {
$redis = new Redis();
list ($host, $port) = explode(':', REDIS_CACHE);
$redis->connect($host, $port);
$key = 'proxy:' . md5($url);
$content = $redis->get($key);
if (false !== $content) {
return $content;
}
}
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_BINARYTRANSFER, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, TIMEOUT);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_MAXREDIRS, 2);
curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);
$encoding = 'UTF-8';
curl_setopt($ch, CURLOPT_HEADERFUNCTION, function ($ch, $line) use (&$encoding) {
list($key, $value) = explode(':', $line, 2);
$key = strtolower(trim($key));
if ($key == 'content-type' && preg_match("/charset=([_a-z0-9-]+)/i", $value, $matches)) {
$encoding = strtoupper($matches[1]);
}
return strlen($line);
});
$result = curl_exec($ch);
if (false === $result) {
curl_close($ch);
return false;
}
if ('UTF-8' !== $encoding) {
$result = mb_convert_encoding($result, 'UTF-8', $encoding);
}
if (isset($redis)) {
$redis->set($key, $result, 300);
}
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
return $result;
}
if (defined('REFERER') && REFERER) {
$referer = $_SERVER['HTTP_REFERER'];
if (empty($referer)) {
exit;
}
$refHost = parse_url($referer, PHP_URL_HOST);
if (empty($refHost) || $refHost != REFERER) {
exit;
}
}
$url = $_GET['url'] ?: NULL;
$callback = $_GET['callback'] ?: 'callback';
if (!preg_match("/^[_a-z0-9]+$/i", $callback)) {
$callback = 'callback';
}
header('Content-Type: application/x-javascript');
if (empty($url)) {
exit;
}
$parts = parse_url($url);
if (false === $parts) {
exit;
}
$host = strtolower($parts['host']);
if ($host == $_SERVER['HTTP_HOST'] || !check_host($host)
|| empty($parts['scheme']) || !preg_match("/^https?$/i", $parts['scheme'])) {
exit;
}
$result = request($url, $status);
if (false === $request) {
exit;
}
$json = json_encode(['contents' => $result, 'status' => $status]);
echo "{$callback}({$json});";
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment