十一博客 十一博客

新浪图床简单反向代理

in 默认类,技术控,分享控 read (830) 文章转载请注明来源!

新建两个文件index.phpCurl.class.php

使用方法:https://tools.67cc.cn/sinaimg/?https://ws1.sinaimg.cn/large/7f0c40d4gy1fqbf9yzk6uj21hc0u0akk.jpg

https://tools.67cc.cn/sinaimg/?https://ws1.sinaimg.cn/large/7f0c40d4gy1fqbf9yzk6uj21hc0u0akk.jpg

index.php代码如下:

<?php
header("Content-Type:image/png");//设置本文档将出输出的格式为png图片
require_once 'Curl.class.php';
$curl = \lib\Curl::main();
$string = $_SERVER["QUERY_STRING"];
$url = strstr($string, "http");
$info = $curl->url($url)->header('User-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36')->get();
echo $info;

Curl.class.php代码如下:

<?php
/**
 * User: Vito
 * Date: 2017/12/20
 * Time: 23:16
 */

/**
 * 使用方法
 * get请求 \lib\Curl::main('http://baidu.com')->get();
 * post请求 \lib\Curl::main()->url('http://baidu.com')data(['username'=>'vito','password'=>'vito123456'])->post();
 * 上传文件 \lib\Curl::main()->url('http://baidu.com')->upload(['ip'=>'./ip.txt','user'=>'user.txt'])->post();
 */

namespace lib;
class Curl
{
    //错误信息
    static private $error_code = array(
        0 => 'No Error',
        1 => '您传送给 libcurl 的网址使用了此 libcurl 不支持的协议。 可能是您没有使用的编译时选项造成了这种情况(可能是协议字符串拼写有误,或没有指定协议 libcurl 代码)。',
        2 => '非常早期的初始化代码失败。 可能是内部错误或问题。',
        3 => '网址格式不正确。',
        5 => '无法解析代理服务器。 指定的代理服务器主机无法解析。',
        6 => '无法解析主机。 指定的远程主机无法解析。',
        7 => '无法通过 connect() 连接至主机或代理服务器。',
        8 => '在连接到 FTP 服务器后,libcurl 需要收到特定的回复。 此错误代码表示收到了不正常或不正确的回复。 指定的远程服务器可能不是正确的 FTP 服务器。',
        9 => '我们无法访问网址中指定的资源。 对于 FTP,如果尝试更改为远程目录,就会发生这种情况。',
        11 => '在将 FTP 密码发送到服务器后,libcurl 需要收到正确的回复。 此错误代码表示返回的是意外的代码。',
        13 => 'libcurl 无法从服务器端收到有用的结果,作为对 PASV 或 EPSV 命令的响应。 服务器有问题。',
        14 => 'FTP 服务器返回 227 行作为对 PASV 命令的响应。 如果 libcurl 无法解析此行,就会返回此代码。',
        15 => '在查找用于新连接的主机时出现内部错误。',
        17 => '在尝试将传输模式设置为二进制或 ascii 时发生错误。',
        18 => '文件传输尺寸小于或大于预期。 当服务器先报告了一个预期的传输尺寸,然后所传送的数据与先前指定尺寸不相符时,就会发生此错误。',
        19 => '‘RETR’ 命令收到了不正常的回复,或完成的传输尺寸为零字节。',
        21 => '在向远程服务器发送自定义 “QUOTE” 命令时,其中一个命令返回的错误代码为 400 或更大的数字(对于 FTP),或以其他方式表明命令无法成功完成。',
        22 => '如果 CURLOPT_FAILONERROR 设置为 TRUE,且 HTTP 服务器返回 >= 400 的错误代码,就会返回此代码。 (此错误代码以前又称为 CURLE_HTTP_NOT_FOUND。)',
        23 => '在向本地文件写入所收到的数据时发生错误,或由写入回调 (write callback) 向 libcurl 返回了一个错误。',
        25 => '无法开始上传。 对于 FTP,服务器通常会拒绝执行 STOR 命令。 错误缓冲区通常会提供服务器对此问题的说明。 (此错误代码以前又称为 CURLE_FTP_COULDNT_STOR_FILE。)',
        26 => '读取本地文件时遇到问题,或由读取回调 (read callback) 返回了一个错误。',
        27 => '内存分配请求失败。 此错误比较严重,若发生此错误,则表明出现了非常严重的问题。',
        28 => '操作超时。 已达到根据相应情况指定的超时时间。 请注意: 自 Urchin 6.6.0.2 开始,超时时间可以自行更改。 要指定远程日志下载超时,请打开 urchin.conf 文件,取消以下行的注释标记:',
        30 => 'FTP PORT 命令返回错误。 在没有为 libcurl 指定适当的地址使用时,最有可能发生此问题。 请参阅 CURLOPT_FTPPORT。',
        31 => 'FTP REST 命令返回错误。 如果服务器正常,则应当不会发生这种情况。',
        33 => '服务器不支持或不接受范围请求。',
        34 => '此问题比较少见,主要由内部混乱引发。',
        35 => '同时使用 SSL/TLS 时可能会发生此错误。 您可以访问错误缓冲区查看相应信息,其中会对此问题进行更详细的介绍。 可能是证书(文件格式、路径、许可)、密码及其他因素导致了此问题。',
        36 => '尝试恢复超过文件大小限制的 FTP 连接。',
        37 => '无法打开 FILE:// 路径下的文件。 原因很可能是文件路径无法识别现有文件。 建议您检查文件的访问权限。',
        38 => 'LDAP 无法绑定。LDAP 绑定操作失败。',
        39 => 'LDAP 搜索无法进行。',
        41 => '找不到函数。 找不到必要的 zlib 函数。',
        42 => '由回调中止。 回调向 libcurl 返回了 “abort”。',
        43 => '内部错误。 使用了不正确的参数调用函数。',
        45 => '界面错误。 指定的外部界面无法使用。 请通过 CURLOPT_INTERFACE 设置要使用哪个界面来处理外部连接的来源 IP 地址。 (此错误代码以前又称为 CURLE_HTTP_PORT_FAILED。)',
        47 => '重定向过多。 进行重定向时,libcurl 达到了网页点击上限。 请使用 CURLOPT_MAXREDIRS 设置上限。',
        48 => '无法识别以 CURLOPT_TELNETOPTIONS 设置的选项。 请参阅相关文档。',
        49 => 'telnet 选项字符串的格式不正确。',
        51 => '远程服务器的 SSL 证书或 SSH md5 指纹不正确。',
        52 => '服务器未返回任何数据,在相应情况下,未返回任何数据就属于出现错误。',
        53 => '找不到指定的加密引擎。',
        54 => '无法将选定的 SSL 加密引擎设为默认选项。',
        55 => '无法发送网络数据。',
        56 => '接收网络数据失败。',
        58 => '本地客户端证书有问题',
        59 => '无法使用指定的密钥',
        60 => '无法使用已知的 CA 证书验证对等证书',
        61 => '无法识别传输编码',
        62 => 'LDAP 网址无效',
        63 => '超过了文件大小上限',
        64 => '请求的 FTP SSL 级别失败',
        65 => '进行发送操作时,curl 必须回转数据以便重新传输,但回转操作未能成功',
        66 => 'SSL 引擎初始化失败',
        67 => '远程服务器拒绝 curl 登录(7.13.1 新增功能)',
        68 => '在 TFTP 服务器上找不到文件',
        69 => '在 TFTP 服务器上遇到权限问题',
        70 => '服务器磁盘空间不足',
        71 => 'TFTP 操作非法',
        72 => 'TFTP 传输 ID 未知',
        73 => '文件已存在,无法覆盖',
        74 => '运行正常的 TFTP 服务器不会返回此错误',
        75 => '字符转换失败',
        76 => '调用方必须注册转换回调',
        77 => '读取 SSL CA 证书时遇到问题(可能是路径错误或访问权限问题)',
        78 => '网址中引用的资源不存在',
        79 => 'SSH 会话中发生无法识别的错误',
        80 => '无法终止 SSL 连接',
    );

    //保存实例对象
    static private $_instance;
    //上次错误号
    private $errno = 0;
    //上次访问信息
    private $request = [];
    //上次响应信息
    private $response = [];
    //选项信息
    protected $option = [
        'url' => null,      //请求的url地址
        'post' => false,    //是否为post请求
        'header' => null,   //请求头参数
        'data' => null,     //post数据
        'upload' => null,   //上传文件
        'cookie' => null,   //请求携带的cookie
        'saveCookie' => false, //是否保存cookie
        'cert' => null,     //证书
        'proxy' => false    //代理
    ];

    //CURL配置信息
    private $config = [
        'CURLOPT_TIMEOUT' => 20,   //请求最大时间
        'CURLOPT_HEADER'  => true  //是否请求header
    ];

    /**
     * Curl 构造方法
     * @param $option string|array
     * 传入字符串将作为url方法参数
     * 传入数组将作为选项信息
     */
    public function __construct($option = ''){
        if($option){
            if(is_array($option)){
                $this->option = array_merge($this->option,$option);
            }else{
                $this->url($option);
            }
        }
    }

    /**
     * main 静态入口
     * @param $option string|array
     * 传入字符串将作为url方法参数
     * 传入数组将作为选项信息
     * @return self
     */
    static public function main($option=''){
        if(!self::$_instance instanceof self){
            self::$_instance = new self;
        }
        if($option){
            if(is_array($option)){
                self::$_instance->option = array_merge(self::$_instance->option,$option);
            }else{
                self::$_instance->url($option);
            }
        }
        return self::$_instance;
    }

     /**
     * 获取最后一次请求错误信息
     * @param bool $flag 为true返回可写入文本的错误信息
     * @return string
     */
    public function getError($flag=false){
        if($flag) return 'errno: '.$this->errno."\r\nerrorMsg: ".self::$error_code[$this->errno];
        return 'errno: '.$this->errno.'<br>errorMsg: '.self::$error_code[$this->errno];
    }

    /**
     * 获取最后一次设置的所有参数
     * @return array
     */
    public function getRequest(){
        return $this->request;
    }

    /**
     * 获取最后一次响应信息
     * @return array
     */
    public function getResponse(){
        return $this->response;
    }

    //魔术方法
    public function __set($key, $value){
        $this->config[$key] = $value;
    }

    /**
     * 设置请求URL
     * @param $url string
     * @return self
     */
    public function url($url){
        $this->option['url'] = $url;
        return $this;
    }

    /**
     * 设置请求数据
     * @param $data array|string
     * @return self
     */
    public function data($data){
        if(is_array($data)){
            $this->option['data'] = http_build_query($data);
        }
        if(is_string($data)){
            $this->option['data'] = $data;
        }
        return $this;
    }

    /**
     * 设置请求头信息
     * @param $data string|array
     * @return self
     */
    public function header($data){
        //传参为数组
        if(is_array($data)){
            foreach ($data as $k => $v){
                $this->option['header'][] = $k.':'.$v;
            }
        }
        //传参为字符串
        if(is_string($data)){
            $this->option['header'][] = $data;
        }
        return $this;
    }

    /**
     * 设置请求cookie
     * @param $data array|string
     * @return self
     * @throws \Exception
     */
    public function cookie($data){
        //传参为字符串
        if(is_string($data)){
            $this->option['cookie'] = $data;
        }
        //传参为数组
        if(is_array($data)){
            $this->option['cookie'] = self::joins('=',';',$data);
        }
        return $this;
    }

    /**
     * @param $path 保存cookie文件地址
     * @return self
     */
    public function saveCookie($path=null){
        if($path){
            $this->option['saveCookie'] = $path;
        }else{
            $this->option['saveCookie'] = 'cookie.txt';
        }
        return $this;
    }

    /**
     * 设置请求上传文件数据
     * @param $data string|array ['ip'=>'ip.txt','user'=>'user.txt']
     * @param $field string 字段名
     * @return self
     * @throws \Exception
     */
    public function upload($file,$field=null){
        try{
            if(is_string($file)){
                $this->isFile($file,$field);
            }
            if(is_array($file)){
                foreach ($file as $k => $v){
                    $this->isFile($v,$k);
                }
            }
        }catch (\Exception $ex){
            exit($ex->getMessage());
        }

/*        if(!is_array($data)){
            $basename = basename($data);
            $file['file'] = [
                'name' => $basename,
                'path' => $data
            ];
            $data = $file;
        }

        foreach ($data as $k => $v){
            //上传文件不存在
            if(!is_file($v['path'])){
                throw new \Exception('上传文件目录不存在“' . $v['path'] . '”');
            }

            //获取文件mime类型
            $mime = mime_content_type($v['path']);
            $head = "{$k}\";filename=\"{$v['name']}\"\r\nContent-Type: {$mime}\r\nm:\"d";
            $content = file_get_contents($v['path']);
            $this->option['upload'][$head] = $content;
        }*/
        return $this;
    }

    /**
     * 设置代理
     * @param $data string|array
     * string  127.0.0.1:8080
     * array    ['host'=>'127.0.0.1','port'=>8080]
     * @return $this
     */
    public function proxy($data){
        if(is_string($data)){
            $arr = explode(':',$data);
            $this->option['proxy']['host'] = $arr[0];
            $this->option['proxy']['port'] = $arr[1];
        }
        if(is_array($data)){
            $this->option['proxy'] = $data;
        }
        return $this;
    }

    /**
     * 发送get请求
     * @param $data array|string
     * @return mixed
     */
    public function get($data=null){
        //检查是否设置了url
        try{
            $this->checkURL();
        }catch(\Exception $ex){
            exit($ex->getMessage());
        }
        $this->option['post'] = false;
        if($data !== null){
            $this->data($data);
        }

        if($this->option['data'] !== null){
            //设置有数据的url
            $this->option['url'] = self::mergeUrlData($this->option['url'], $this->option['data']);
        }
        //执行请求
        return $this->exec();
    }

    /**
     * 发起post请求
     * @param $data array|string
     * @return mixed
     */
    public function post($data=null){
        //检查url是否为空
        try{
            $this->checkURL();
        }catch(\Exception $ex){
            exit($ex->getMessage());
        }
        //设置请求为post
        $this->option['post'] = true;
        if($data !== null){
            $this->data($data);
        }

        //有文件上传
        if($this->option['upload'] !== null){
            if($this->option['data'] !== null){
                parse_str($this->option['data'],$query_arr);
                $this->option['data'] = array_merge($query_arr,$this->option['upload']);
            }else{
                $this->option['data'] = $this->option['upload'];
            }
        }
        return $this->exec();
    }

    /**
     * 将关联数组拼接为指定字符串
     * @param $str 关联数组键值连接符
     * @param $str1 数组分隔符
     * @param $arr 关联数组
     * @return string
     * @throws \Exception
     */
    static public function joins($str,$str1,$arr){
        //非数组
        if(!is_array($arr)){
            throw new \Exception('参数$arr必须为数组');
        }
        $arrs = array();
        //拼接
        foreach ($arr as $k => $v){
            $arrs[] = "{$k}{$str}{$v}";
        }
        return join($str1,$arrs);
    }

    /**
     * 设置证书
     * @param string $certPath 公钥证书路径
     * @param string $keyPath 私钥证书路径
     * @return self
     */
    public function certificate($certPath, $keyPath = ''){
        $this->option['cert']['certPath'] = $certPath;
        if (!empty($keyPath))
            $this->option['cert']['keyPath'] = $keyPath;
        return $this;
    }

    /**
     * 执行curl函数请求
     * @return mixed
     */
    protected function exec(){
        $ch = curl_init();
        //设置请求地址
        curl_setopt($ch,CURLOPT_URL,$this->option['url']);
        //显示响应头
        curl_setopt($ch, CURLOPT_HEADER, $this->config['CURLOPT_HEADER']);
        //是否自动显示内容
        curl_setopt($ch, CURLOPT_RETURNTRANSFER,true);
        //是否执行post请求
        curl_setopt($ch,CURLOPT_POST,$this->option['post']);

        //循环配置并给CURL设置属性
        foreach ($this->config as $option => $val){
            curl_setopt($ch, constant($option), $val);
        }

        //请求https协议
        if(strtolower(parse_url($this->option['url'])['scheme']) == 'https'){
            curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,false); //对认证证书来源检查
            curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,false); //从证书中检查SSL加密算法

            if($this->option['cert']){
                if (count($this->option['cert']) == 2) {
                    curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'PEM');
                    curl_setopt($ch, CURLOPT_SSLCERT, $this->option['cert']['certPath']);
                    //默认格式为PEM,可以注释
                    curl_setopt($ch, CURLOPT_SSLKEYTYPE, 'PEM');
                    curl_setopt($ch, CURLOPT_SSLKEY, $this->option['cert']['keyPath']);
                }else{
                    curl_setopt($ch, CURLOPT_SSLCERT, $this->option['cert']['certPath']);
                }
            }
        }

        if($this->option['post'] === true){
            //post请求数据设置
            curl_setopt($ch,CURLOPT_POSTFIELDS,$this->option['data']);
            curl_setopt($ch,CURLOPT_BINARYTRANSFER,true);
        }

        if($this->option['header'] !== null){
            //请求头数据设置
            curl_setopt($ch,CURLOPT_HTTPHEADER,$this->option['header']);
        }

        if($this->option['cookie'] !== null){
            //请求携带cookie设置
            curl_setopt($ch,CURLOPT_COOKIE,$this->option['cookie']);
        }

        if($this->option['proxy'] !== false){
            //设置代理
            curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_BASIC); //代理认证模式
            curl_setopt($ch, CURLOPT_PROXY, $this->option['proxy']['host']); //代理服务器地址
            curl_setopt($ch, CURLOPT_PROXYPORT,$this->option['proxy']['port']); //代理服务器端口
        }

        $result = curl_exec($ch);

        //赋值给对象属性
        $this->request = $this->option;
        //重置选项属性
        $this->unOption();

        //获取内容出错
        if($result === false || $result === null){
            $this->errno = curl_errno($ch);
            return false;
        }

        //header长度
        $headLength = curl_getinfo($ch,CURLINFO_HEADER_SIZE);

        //截取内容
        if($this->config['CURLOPT_HEADER']) {
            $this->response['header']['Set-Cookie'] = '';
            $header = substr($result, 0, $headLength);
            $expHea = explode("\r\n", $header);
            foreach($expHea as $v) {
                if(empty($v))
                    continue;
                $hea = explode(':', $v, 2);
                if(count($hea) == 1) {
                    $this->response['header'][] = trim($hea[0]);
                }else{
                    if(strpos($hea[0],'Cookie')){
                        $this->response['header']['Set-Cookie'] .= trim($hea[1])."; ";
                    }else{
                        $this->response['header'][$hea[0]] = trim($hea[1]);
                    }
                }
            }
            $this->response['header']['Set-Cookie'] = rtrim($this->response['header']['Set-Cookie'],'; ');
            $this->response['code'] = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            $this->response['body'] = substr($result, $headLength);
        }else{
            $this->response['body'] = $result;
        }

        if($this->request['saveCookie'] !== false){
            //保存此次请求cookie
            $time = date('Y-m-d H:i:s');
            $cookie = "URL\t\t:\t{$this->request['url']}\r\nTime\t:\t${time}\r\nCookie\t:\t{$this->response['header']['Set-Cookie']}\r\n\r\n";
            file_put_contents($this->request['saveCookie'],$cookie,FILE_APPEND);
        }

        //关闭释放curl
        curl_close($ch);
        return $this->response['body'];

    }

    /**
     * URL数据合并处理
     * @param $url
     * @param $data
     * @return string
     */
    private function mergeUrlData($url,$data){
        $parse_url = parse_url($url);
        $url = "{$parse_url['scheme']}://{$parse_url['host']}";
        if(isset($parse_url['port'])){
            $url .= ":{$parse_url['port']}";
        }
        $url .= "{$parse_url['path']}?";
        if(isset($parse_url['query'])){
            $url .= "{$parse_url['query']}&";
        }
        $url .= $data;
        return $url;
    }

    /**
     * 检查文件是否存在
     * 存在就上传
     * @param $file 文件路径
     * @param $field 上传文件字段
     * @return bool
     * @throws \Exception
     */
    private function isFile($file,$field){
        if(!is_file($file)){
            throw new \Exception('上传'.$file.'文件不存在');
        }
        $this->option['upload'][$field] = new \CURLFile($file);
        return true;
    }

    /**
     * 检查URL是否为空
     * @throws \Exception
     */
    private function checkURL(){
        if($this->option['url'] === null){
            throw new \Exception('URL地址不能为空,请设置');
        }
        return true;
    }

    private function unOption(){
        $this->option = [
        'url' => null,      //请求的url地址
        'post' => false,    //是否为post请求
        'header' => null,   //请求头参数
        'data' => null,     //post数据
        'upload' => null,   //上传文件
        'cookie' => null,   //请求携带的cookie
        'saveCookie' => false, //是否保存cookie
        'cert' => null,     //证书
        'proxy' => false    //代理
    ];
    }


}

本文基于《署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)》许可协议授权
文章链接:https://blog.67cc.cn/archives/sina-map-bed-simple-reverse-agent.html (转载时请注明本文出处及文章链接)

代码记录教程分享
发表新评论
已有 3 条评论
  1. 梦魂
    梦魂 7Chrome 74
    回复

    有条件的话,还是存到服务器要好很多,像公共图床的话,不稳……(新浪防盗链吓得我赶紧转移

  2. 凌一
    凌一 10QQ浏览器 10
    回复

    老哥别怂,直接怼个服务器上去。

    1. 十一
      十一本文作者 10Chrome 69
      回复

      @凌一 可以 但没必要

❋该站点已苟活
© 2017-2019 十一博客 蜀ICP备15021123号-1
又拍云
PREVIOUS NEXT
雷姆
拉姆