<?php
/**
 * 代理搜刮
 */
class getProxy {
    protected $db;
    protected $debug_mode = 0;  // 调试开关
    protected $proxy_url;
    protected $page;
    protected $end=0;

    function __construct( $db ) {
        $this -> db = $db;
        $this -> page = isset($_GET['p']) ? (int)$_GET['p'] : 1;
    }

    /**
     * 采集代理
     * @return
     */
    public function exec() {
        $table = 'proxy';
        do {
            $proxy_url  = $this -> proxy_url . $this -> page;
            $datas      = $this -> curlRequest($proxy_url);
            if( $datas ) {
                foreach( $datas as $data ) {
                    $data['source']    = 2; // 来源为采集
                    $data['add_time']  = date('Y-m-d H:i:s');
                    $data['used_date'] = '0000-00-00 00:00:00';
                    $data['times']     = 0;

                    $this -> cookie_jar = dirname( dirname(__FILE__) ) . '/tmp/' . $data['ip'] . '.pt.cookie';
                    if( is_file( $this -> cookie_jar ) ) {  // 清除Cookie文件
                        @unlink( $this -> cookie_jar );
                    }
                    $formData  = array(
                                    'LOOKUPADDRESS' => $data['ip'],
                                    'Lookup IP Address' => 'Lookup IP Address',
                                );
                    if( $this -> checkProxy( $data, $data['http_type'], $formData) ) {    // 检测代理是否有效
                        // 使用IP
                        $where['ip']   = $data['ip'];
                        $ipData = $this -> db -> get($table, array('id'), $where);
                        if( $ipData ) {
                        } else {
                            $this -> db -> insert($table, $data);
                        }
                    }
                }
            }
            $this -> page += 1;
            sleep(1);
        } while($this -> end == 1);
    }

    /**
     * 重置IP次数
     * 今日添加的代理IP并且上次加入时间超过1小时，使用次数清零。
     * @return
     */
    public function filterProxy () {
        $table  = 'proxy';
        $fields = array('id', 'ip', 'port', 'http_type');
        $where['add_time[<]'] = date( 'Y-m-d H:i:s', strtotime( '-65 minutes' ) );
        $proxys = $this -> db -> select( $table, $fields, $where );

        if( $proxys ) {
            foreach( $proxys as $proxy ) {
                $_where['id'] = $proxy['id'];
                $this -> cookie_jar = dirname( dirname(__FILE__) ) . '/tmp/' . $proxy['ip'] . '.pt.cookie';
                if( is_file( $this -> cookie_jar ) ) {              // 清除Cookie文件
                    @unlink( $this -> cookie_jar );
                }
                $formData  = array(
                                'LOOKUPADDRESS' => $proxy['ip'],
                                'Lookup IP Address' => 'Lookup IP Address',
                            );
                if( $this -> checkProxy( $proxy, $proxy['http_type'], $formData ) ) {
                    $proxy['add_time'] = date('Y-m-d H:i:s');
                    $proxy['times']    = 0;
                    $this -> db -> update($table, $proxy, $_where);
                } else {
                    $this -> db -> delete($table, $_where);
                }
            }
        }
    }

    /**
     * 输出一个代理IP地址
     * @return [json]
     */
    public function sendIp() {}

    /**
     * 获取采集代理IP的网址
     * @return [type] [description]
     */
    public function getProxyUrl() {
        return $this -> proxy_url;
    }

    /**
     * [getProxyByApi 通过付费API获取代理IP]
     * @return [Array]
     */
    public function getProxyByApi() {
        $proxy_url = PROXY_API_URL;
        if(defined('PROXY_API_NUM') && PROXY_API_NUM !== '' ) {
            $proxy_url .= '&num=' . PROXY_API_NUM;
        }
        if( defined('PROXY_API_COUNTRY') && PROXY_API_COUNTRY !== '' ) {
            $proxy_url .= '&country=' . PROXY_API_COUNTRY;
        }
        if( defined('PROXY_API_PORT') && PROXY_API_PORT !== '' ) {
            $proxy_url .= '&port=' . PROXY_API_PORT;
        }
        if( defined('PROXY_API_HTTP_TYPE') && PROXY_API_HTTP_TYPE !== '' ) {
            $proxy_url .= '&http_type=' . PROXY_API_HTTP_TYPE;
        }
        if( defined('PROXY_API_ANONYMOUS') && PROXY_API_ANONYMOUS !== '' ) {
            $proxy_url .= '&anonymous=' . PROXY_API_ANONYMOUS;
        }
        if( defined('PROXY_API_ISP') && PROXY_API_ISP !== '' ) {
            $proxy_url .= '&isp=' . PROXY_API_ISP;
        }
        if( defined('PROXY_API_PING_TIME') && PROXY_API_PING_TIME !== '' ) {
            $proxy_url .= '&ping_time=' . PROXY_API_PING_TIME;
        }
        if( defined('PROXY_API_TRANSFER_TIME') && PROXY_API_TRANSFER_TIME !== '' ) {
            $proxy_url .= '&transfer_time=' . PROXY_API_TRANSFER_TIME;
        }
        if( defined('PROXY_API_RESULT_FIELDS') && PROXY_API_RESULT_FIELDS !== '' ) {
            $proxy_url .= '&result_fields=' . PROXY_API_RESULT_FIELDS;
        }
        if( defined('PROXY_API_RESULT_SORT_FIELDS') && PROXY_API_RESULT_SORT_FIELDS !== '' ) {
            $proxy_url .= '&result_sort_field=' . PROXY_API_RESULT_SORT_FIELDS;
        }
        if( defined('PROXY_API_RESULT_FORMAT') && PROXY_API_RESULT_FORMAT !== '' ) {
            $proxy_url .= '&result_format=' . PROXY_API_RESULT_FORMAT;
        }
        $jsonData = $this -> httpGet( $proxy_url );
        $jsonData = json_decode( $jsonData, true );

        if ( isset($jsonData['code']) && empty($jsonData['result']) ) {
            $gShow['errcode'] = -1;
            $gShow['errmsg']  = $jsonData['code_msg'];
        } else {
            $gShow['errcode'] = 0;
            $gShow['errmsg']  = 'success!';
            $results          = $jsonData['result'];
            // $results = array( array('ip:port'=>'119.59.126.44:9999', 'http_type'=>'http', 'anonymous'=>'') );

            foreach ( $results as $data ) {
                $tmp  = explode(':', $data['ip:port']);
                $this -> cookie_jar = dirname( dirname(__FILE__) ) . '/tmp/' . $tmp[0] . '.pt.cookie';
                $formData  = array(
                            'LOOKUPADDRESS' => $tmp[0],
                            'Lookup IP Address' => 'Lookup IP Address',
                        );
                $proxy['ip']   = $tmp[0];
                $proxy['port'] = $tmp[1];
                if( $this -> checkProxy( $proxy, $data['http_type'], $formData ) ) {
                    switch( strtolower($data['http_type']) ) {
                        case 'http':
                            $proxy['http_type'] = 1;
                        break;
                        case 'https':
                        case 'http/https':
                            $proxy['http_type'] = 2;
                        break;
                        case 'socks4':
                            $proxy['http_type'] = 4;
                        break;
                        case 'socks5':
                        case 'socks4/socks5':
                            $proxy['http_type'] = 5;
                        break;
                    }
                    if ( preg_match('/高匿/i', $data['anonymous']) ) {
                        $proxy['type'] = 1;
                    } elseif( preg_match('/透明/i', $data['anonymous']) ) {
                        $proxy['type'] = 2;
                    } else {
                        $proxy['type'] = 5;
                    }
                    // 使用IP
                    $where['ip']   = $proxy['ip'];
                    $ipData = $this -> db -> get($table, array('id'), $where);
                    if( ! $ipData ) {
                        $this -> db -> insert('proxy', $proxy);
                    }
                }
            }
        }
        $this -> returnJson($gShow, 'JSON');
    }

    /**
     * [curlRequest Curl请求采集代理]
     * @param  [type]  $url       [请求地址]
     * @param  string  $postData  [表单数据]
     * @param  boolean $return_data  [是否返回数据]
     * @param  boolean $ssl       [是否SSL加密请求]
     * @return [Mixed]
     */
    function curlRequest ($url, $postData='', $return_data=true, $ssl=false) {
        $curl = curl_init();
        // Set SSL if required
        if ( $ssl ) {
            curl_setopt($curl, CURLOPT_PORT, 443);
        }
        curl_setopt($curl, CURLOPT_HEADER, 1);
        curl_setopt($curl, CURLINFO_HEADER_OUT, false);
        curl_setopt($curl, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36");
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($curl, CURLOPT_FORBID_REUSE, false);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, $return_data);
        curl_setopt($curl, CURLOPT_URL, $url);
        if( $postData ) {
            curl_setopt($curl, CURLOPT_POST, true);
            curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($postData));
        }

        $data = curl_exec($curl);
        if($this -> debug_mode == 1 && curl_errno($curl) > 0) {
            $error = sprintf('警告：CURL错误 %s(%s)！', curl_error($curl), curl_errno($curl));
            echo "<pre>";
            echo $error;
            echo "</pre>";
        }
        curl_close($curl);
        if ( $data ) {
            return $this -> prase_data( $data );
        } else {
            return false;
        }
    }

    /**
     * 解析返回的HTML页面
     * @return Array
     */
    protected function prase_data( $data ) {
        $regx = '/<table[^>]+class=[\"\']{0,1}proxy_table[\"\']{0,1}[^>]+>([\w\W]+?)<\/table>/i';
        if ( preg_match( $regx, $data, $matches ) ) {
            $info = $matches[1];
            $_regx = '/<tr[^>]+>([\w\W]+?)<\/tr>/i';
            if( preg_match_all( $_regx, $info, $rows ) ) {
                $rows = array_shift( $rows );
                array_shift($rows);
                $regx_row = '/<td[^>]*>([\w\W]+?)<\/td>/i';
                $proxyData = array();
                foreach( $rows as $key => $row ) {
                    if( preg_match_all($regx_row, $row, $datas) ) {
                        $datas = array_shift( $datas );
                        foreach($datas as $_key => $data) {
                            if( $data ) {
                                $data = trim($data);
                                switch($_key) {
                                    case 0 :        // IP
                                        $proxyData[$key]['ip'] = trim ( strip_tags( $data ) );
                                    break;
                                    case 1 :        // 端口
                                        $proxyData[$key]['port'] = trim ( strip_tags( $data ) );
                                    break;
                                    case 3:
                                        if ( preg_match('/https/i', strtolower($data)) ) {
                                            $proxyData[$key]['http_type'] = 2;
                                        } else {
                                            $proxyData[$key]['http_type'] = 1;
                                        }
                                    break;
                                    case 4 :        // 代理类型
                                        if (preg_match('/高匿/i', $data)) {
                                            $proxyData[$key]['type'] = 1;
                                        } else {
                                            $proxyData[$key]['type'] = 2;
                                        }
                                    break;
                                    case 5 :        // 检测时间
                                        // if( date('Y-m-d', strtotime($data)) != date('Y-m-d') && $this -> page > 50 ) {
                                        //     // 终止抓取
                                        //     $this -> end = 1;
                                        // }
                                    break;
                                    case 6 :        // 过滤速度超时的IP
                                        if ( (int)$data > 500 || preg_match('/超时/i', $data)) {
                                            // 终止抓取
                                            unset ( $proxyData[$key] ); // 删除超时IP
                                            $this -> end = 1;
                                        }
                                    break;
                                }
                            }
                        }
                    }
                }
                $proxyData = array_values($proxyData);
            }  else {
                return false;
            }
        } else {
            return false;
        }
        return $proxyData;
    }

    /**
     * 返回数据结果
     * @param  [type] $jsonData [数据]
     * @param  [type] $type     [JSON/JSONP/HTML]
     * @return [type]           [返回格式化数据]
     */
    public function returnJson ($data, $type='', $json_option=0) {
        if(empty($type)) $type  =   'JSON'; //默认返回JSON数据
        switch (strtoupper($type)){
            case 'JSON' :
                // 返回JSON数据格式到客户端 包含状态信息
                header('Content-Type:application/json; charset=utf-8');
                exit(json_encode($data, $json_option));
            case 'XML'  :
                // 返回xml格式数据
                header('Content-Type:text/xml; charset=utf-8');
                exit(xml_encode($data));
            case 'JSONP':
                // 返回JSON数据格式到客户端 包含状态信息
                header('Content-Type:application/json; charset=utf-8');
                $handler  =   isset($_GET['callback']) ? $_GET['callback'] : 'callback';
                exit($handler.'('.json_encode($data,$json_option).');');
            case 'EVAL' :
                // 返回可执行的js脚本
                header('Content-Type:text/html; charset=utf-8');
                exit($data);
        }
    }

    public function setParam( $param, $value ) {
        $this->{$param} = $value;
        return $this;
    }

    public function getParam( $param ) {
        return $this->{$param};
    }

    /**
     * 检测代理是否有效
     * @return [type] [description]
     */
    public function checkProxy( $proxy = '', $socks = '', $postData='', $check_url="", $timeout = 5 ) {
        if( strtolower($socks) == 'socks4' || (is_numeric($socks) && $socks == 4) ) {
            $proxytype = CURLPROXY_SOCKS4;
        } elseif( strtolower($socks) == 'socks5' || (is_numeric($socks) && $socks == 5) ) {
            $proxytype = CURLPROXY_SOCKS5;
        } elseif( strtolower($socks) == 'http' || (is_numeric($socks) && $socks == 1) ) {
            $proxytype = CURLPROXY_HTTP;
        } elseif( strtolower($socks) == 'https' || (is_numeric($socks) && $socks == 2) ) { //默认HTTPS
            return false;
        } else {
            $proxytype = CURLPROXY_HTTP;
        }

        if( !$check_url ) {
            $check_url = "http://whatismyipaddress.com/ip-lookup";
        }

        $ch = curl_init();
        $refer = 'http://whatismyipaddress.com/ip-lookup';
        $header = array('Host: whatismyipaddress.com');
        curl_setopt($ch, CURLOPT_URL, $check_url);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
        curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
        curl_setopt($ch, CURLOPT_HEADER, 1);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
        curl_setopt($ch, CURLOPT_REFERER, $refer);
        curl_setopt($ch, CURLINFO_HEADER_OUT, false);
        curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36");
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_FORBID_REUSE, false);

        if( is_array($proxy) ) {
            curl_setopt($ch, CURLOPT_PROXY, $proxy['ip']);
            curl_setopt($ch, CURLOPT_PROXYPORT, $proxy['port']);
        } else {
            curl_setopt($ch, CURLOPT_PROXY, $proxy);
        }
        curl_setopt($ch, CURLOPT_PROXYTYPE, $proxytype);
        curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, 0);
        $cookie_jar = $this -> cookie_jar;

        if( $postData ) {
            curl_setopt($ch, CURLOPT_POST, true);
            curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query( $postData ));
            curl_setopt($ch, CURLOPT_COOKIEJAR,  $cookie_jar);
        } else {
            curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie_jar);
        }

        $response = curl_exec($ch);
        $errno    = curl_errno($ch);
        $error    = curl_error($ch);
        curl_close($ch);
        if( $errno == 0 ) {
            // var_dump($response);
            return trim($response);
        } else {
            $error = sprintf( '警告：CURL错误 %s(%s)！', $error, $errno );
            // echo $error . "\n\r";
            return false;
        }
    }

    /**
     * 接口请求方法
     */
    public function httpGet($url, $refer='', $follow=false, $maxredirs=10) {
        $ch = curl_init($url);
        $options = array(
                CURLOPT_RETURNTRANSFER => true,         // return web page
                CURLOPT_HEADER         => false,        // don't return headers
                CURLOPT_FOLLOWLOCATION => $follow,      // follow redirects
                CURLOPT_ENCODING       => "",           // handle all encodings
                CURLOPT_USERAGENT      => "",           // who am i
                CURLOPT_AUTOREFERER    => true,         // set referer on redirect
                CURLOPT_CONNECTTIMEOUT => 50,            // timeout on connect
                CURLOPT_TIMEOUT        => 50,            // timeout on response
                CURLOPT_MAXREDIRS      => $maxredirs,   // stop after xx redirects
                CURLOPT_SSL_VERIFYHOST => 0,            // don't verify ssl
                CURLOPT_SSL_VERIFYPEER => false,
                CURLOPT_COOKIEFILE     =>'./',
                CURLOPT_COOKIEJAR      =>'./',
                CURLOPT_REFERER        =>$refer,
        );
        curl_setopt_array($ch, $options);
        $result = curl_exec($ch);
        curl_close($ch);
        return $result;
    }

    /**
     * [isPublicIp 判断是否是合法的公共IPv4地址，192.168.1.1这类的私有IP地址将会排除在外]
     * @return boolean [description]
     */
    public function isPublicIp( $ip ) {
        if(filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE)) {
            return true;
        }

        return false;
    }
}
