港股股票接口访问的问题

Posted Jetz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了港股股票接口访问的问题相关的知识,希望对你有一定的参考价值。

18年做了一个小程序“盯盘帮手”,就是监控价格提醒,结果腾讯审核不让过,说是证券业务,无语!。最近发现又可以通过了,于是捡起来继续完善。一个大的改进,想增加港股的支持。结果发现,收到的信息居然晚了15分钟。这是我用的腾讯接口的数据:

v_hk00700=\\"100~腾讯控股~00700~351.600~344.400~352.000~1602628.0~0~0~351.600~0~0~0~0~0~0~0~0~0~351.600~0~0~0~0~0~0~0~0~0~1602628.0~2023/05/02 09:41:06~7.200~2.09~354.400~350.000~351.600~1602628.0~563467129.800~0~15.97~~0~0~1.28~33649.9106~33649.9106~TENCENT~5.88~416.600~180.470~2.49~-17.75~0~0~0~0~0~15.97~4.20~0.02~100~11.31~1.91~GP~26.00~11.91~-5.23~-8.63~-8.68~9570509275.00~9570509275.00~15.97~20.683~351.589~21.46~HKD~1\\";\\n

没办法,找找别家的,结果发现都不好用。费劲把新浪接口恢复起来,还是晚15分钟,数据比腾讯还少:

var hq_str_hk00700=\\"TENCENT,腾讯控股,352.000,344.400,354.400,343.400,344.600,0.200,0.058,344.39999,344.60001,1222677476,3495507,0.000,0.000,416.600,188.626,2023/05/02,10:24\\";\\n

最后,发现问题根源在港交所,人家规定就是必须要晚15分钟

港股数据分BMP基础数据和卓越高级数据,基础数据港交所规定需展示延迟15分钟以上数据,并且也需要找一家行情供应商对接并且需要向港交所按月支付使用授权费,接口是API主动请求的。港股BMP是延迟15分钟行情,高级行情分为L1五档及L2十档行情,并且基础行情是没有包含逐笔成交明细,买卖盘口等。(https://blog.csdn.net/weixin_54618632/article/details/112668316

只好作罢,想想其他的办法。

历年沪深A股香港H股票数据导入和实时数据更新展示 ---转载


【项目需求】

把以CSV文件格式保存的历年历年沪深A股、香港H股票数据导入数据库,如沪深每日财务数据、沪深板块分类数据、沪深历年十大股东变迁数据、港股实时5分钟数据统计等,并且需要从供应商接口实时采集最新股票价格、成交信息并展示给投资者。

【项目疑难点】

文件数据大、种类多,部分数据格式、日期的转换。
实时数据更新要求响应快,采集程序需要高效可靠。

【代码举例】

StockImport.class.php  股票数据导入统一接口类

[php] view plain copy
<?php defined(IN_HEAVEN) or die(Hacking Attempt!);  
/** 
 * 股票数据导入 
 *  
 * PHP version 5 
 *  
 * @category    4SWeb 
 * @package     Admin 
 * @subpackage  Custom 
 * @version     SVN: $Id: StockImport.class.php 67 2014-11-25 15:12:29Z blin.z $ 
 */  
import(COM.GZNC.Import.CSVImport);  
import(ORG.Util.SQLKit);  
import(ORG.Util.File);  
import(ORG.Util.String);  
  
class StockImport extends CSVImport{  
    const ERR_GUESS_FILE = 1201; // 文件名不对  
      
    /** 
     * 数据类型 
     * @var const 
     */  
    // 沪深  
      
    /** 
     * 沪深每日财务数据(2008年3月18日前,37项) 
     * @var const 
     */  
    const SHSZ_FINANCE37 = SHSZ_finance37; // 沪深每日财务数据(2008年3月18日前,37项)  
      
    /** 
     * 沪深每日财务数据(2008年3月19日起,51项) 
     * @var const 
     */  
    const SHSZ_FINANCE = SHSZ_finance; // 沪深每日财务数据(2008年3月19日起,51项)  
      
    /** 
     * 沪深板块分类数据 
     * @var const 
     */  
    const SHSZ_BLOCK = SHSZ_block; // 沪深板块分类数据  
      
    /** 
     * 沪深历年财务报表明细数据_利润表 
     * @var const 
     */  
    const SHSZ_INCOME_STATEMENT = SHSZ_income_statement; // 沪深历年财务报表明细数据_利润表  
      
    /** 
     * 沪深历年财务报表明细数据_现金流量表 
     * @var const 
     */  
    const SHSZ_CASHFLOW_STATEMENT = SHSZ_cashflow_statement; // 沪深历年财务报表明细数据_现金流量表  
      
    /** 
     * 沪深历年财务报表明细数据_资产负债表 
     * @var const 
     */  
    const SHSZ_BALANCE_SHEET = SHSZ_balance_sheet; // 沪深历年财务报表明细数据_资产负债表  
      
    /** 
     * 沪深历年财务报表明细数据_相关91项分析指标 
     * @var const 
     */  
    const SHSZ_FINANCIAL_ANALYSIS_INDEX = SHSZ_financial_analysis_index; // 沪深历年财务报表明细数据_相关91项分析指标  
      
    /** 
     * 沪深历年股本变动数据 
     * @var const 
     */  
    const SHSZ_CAPITAL_STOCK = SHSZ_capital_stock; // 4-沪深历年股本变动数据  
      
    /** 
     * 沪深历年十大股东变迁数据 
     * @var const 
     */  
    const SHSZ_SHAREHOLDER = SHSZ_shareholder; // 5-沪深历年十大股东变迁数据  
      
    /** 
     * 沪深历年十大流通股东变迁数据 
     * @var const 
     */  
    const SHSZ_TRADABLE_SHAREHOLDER = SHSZ_tradable_shareholder; // 5-沪深历年十大流通股东变迁数据  
      
    /** 
     * 沪深日线数据 
     * @var const 
     */  
    const SHSZ_DAY = SHSZ_day; // 6-沪深日线数据  
      
    /** 
     * 沪深日线数据(向前复权) 
     * @var const 
     */  
    const SHSZ_DAY_FORWARD = SHSZ_day_forward; // 6-沪深日线数据 向前复权  
      
    /** 
     * 沪深5分钟数据 
     * @var const 
     */  
    const SHSZ_5MIN = SHSZ_5Min; // 6-沪深5分钟数据  
      
    /** 
     * 沪深5分钟数据(向前复权) 
     * @var const 
     */  
    const SHSZ_5MIN_FORWARD = SHSZ_5Min_forward; // 6-沪深5分钟数据 向前复权  
      
    /** 
     * 沪深权息数据 
     * @var const 
     */  
    const SHSZ_SPLIT = SHSZ_split; // 6-沪深权息数据  
      
    /** 
     * 沪深实时数据 
     * @var const 
     */  
    const SHSZ_REALTIME = SHSZ_realtime; // 6-沪深实时数据  
      
    /** 
     * 沪深实时5分钟数据统计 
     * @var const 
     */  
    const SHSZ_REALTIME_5MIN = SHSZ_realtime_5Min; // 沪深实时5分钟数据统计  
      
    // 港股  
      
    /** 
     * 港股财务数据 
     * @var const 
     */  
    const HK_FINANCE = HK_finance; // 港股财务数据  
      
    /** 
     * 港股行业数据 
     * @var const 
     */  
    const HK_INDUSTRY = HK_industry; // 港股行业数据  
      
    /** 
     * 港股日线数据 
     * @var const 
     */  
    const HK_DAY = HK_day; // 港股日线数据  
      
    /** 
     * 港股日线数据(向前复权) 
     * @var const 
     */  
    const HK_DAY_FORWARD = HK_day_forward; // 港股日线数据 向前复权  
      
    /** 
     * 港股5分钟数据 
     * @var const 
     */  
    const HK_5MIN = HK_5Min; // 港股5分钟数据  
      
    /** 
     * 港股5分钟数据 向前复权 
     * @var const 
     */  
    const HK_5MIN_FORWARD = HK_5Min_forward; // 港股5分钟数据 向前复权  
      
    /** 
     * 港股权息数据 
     * @var const 
     */  
    const HK_SPLIT = HK_split; // 港股权息数据  
      
    /** 
     * 港股实时数据 
     * @var const 
     */  
    const HK_REALTIME = HK_realtime; // 港股实时数据  
      
    /** 
     * 港股实时5分钟数据统计 
     * @var const 
     */  
    const HK_REALTIME_5MIN = HK_realtime_5Min; // 港股实时5分钟数据统计  
      
    /** 
     * 监听类型 
     */  
    const LISTENER_IMPORT_RESULT = 1;  
      
    /** 
     * 监听器 
     * @var array 
     */  
    protected static $_listners = array();  
      
    /** 
     * 统计 
     * @var array 
     */  
    protected $_stats = array();  
      
    /** 
     * 当前数据驱动 
     * @var string 
     */  
    protected $_driver = NULL;  
      
    /** 
     * SQL模式 
     * @var mixed 
     */  
    protected $_sql_mode = ‘‘;  
      
    /** 
     * 每日下载目录 
     * @param string 
     */  
    protected $_down_path = ./WStockDown/;  
      
    /** 
     * 每日更新目录 
     * @param string 
     */  
    protected $_update_path = ./WStockUpdate/;  
      
    /** 
     * 实时更新目录 
     * @param string 
     */  
    protected $_realtime_path = ./WStockRealtime/;  
      
    /** 
     * 日志目录 
     * @param string 
     */  
    protected $_log_path = ./WStockLog/;  
      
    /** 
     * 数据库日志id 
     */  
    protected $_log_id = NULL;  
      
    /** 
     * 是否写SQL语句日志 
     */  
    protected $_log_sql = false;  
      
    /** 
     * 是否为更新导入 
     * @param boolean 
     */  
    protected $_is_update = false;  
      
    /** 
     * 文件默认年份 
     * @var string 
     */  
    protected $_default_file_year = NULL;  
      
    /** 
     * 表格字段定义 
     * @var array 
     */  
    protected static $_fields_maps = NULL;  
      
  
      
    /** 
     * 最后一条SQL 
     * @var string 
     */  
    protected $_last_sql = NULL;  
      
    public function __construct($driver=stockimport){  
        $this->_driver = $driver;  
          
        // 导入工作目录  
        $stock_path = ($t=C(STOCK_WORK_PATH))?$t:DATA_PATH;  
          
        $this->_down_path = $stock_path . WStockDown/;  
        $this->_update_path = $stock_path . WStockUpdate/;  
        $this->_realtime_path = $stock_path . WStockRealtime/;  
        $this->_log_path = $stock_path . WStockLog/;  
          
        /* 
        if(!file_exists($this->_update_path) && !mkdir($this->_update_path)){ 
            return $this->_trigger_error("Cann‘t create update path {$this->_update_path}", SCRIPT_ERR_CONFIG, $this->_update_path, __FILE__, __LINE__); 
        }*/  
          
        /* 
        if(!file_exists($this->_log_path) && !mkdir($this->_log_path)){ 
            return $this->_trigger_error("Cann‘t create log path {$this->_log_path}", SCRIPT_ERR_CONFIG, $this->_log_path, __FILE__, __LINE__); 
        }*/  
          
        //$this->_log = $log_dir . ‘/‘ .  $this->_driver . ‘_‘ . date(‘Ymd‘) . ‘.log‘;  
          
        $log_dir = $this->_get_log_dir(date(Y-m-d), true);  
        $this->_log = $log_dir .  $this->_driver. _ . date(Ymd) . .log;  
          
        $this->_logLevel = ($l=C(STOCK_IMPORT_LOG_LEVEL))?$l:Log::INFO;  
          
        // 忽略空数据、文件不存在错误  
        $this->_ignoreError = array(self::ERR_EMPTY_DATA, self::ERR_FILE_READ, self::ERR_HTTP_REQUEST, self::ERR_GUESS_FILE);  
          
        // 是否把SQL语句写入日志?  
        $this->_log_sql = C(STOCK_IMPORT_LOG_SQL);  
    }  
      
    /** 
     * 数据导入实例工厂 
     * @param string $driver 数据类型名称 
     * @return object 
     */  
    public static function factory($driver){  
        $class = ucfirst(preg_replace("/_([a-zA-Z0-9])/e", "strtoupper(‘\\1‘)", $driver));  
        if(!class_exists($class)){  
            require Drivers/ . $class . .class.php;  
        }  
          
        if(!class_exists($class)){  
            return self::throw_exception("Driver {$driver} not exists", SCRIPT_ERR_CONFIG, $driver, __FILE__, __LINE__);  
        }  
  
        $obj = new $class($driver);  
        return $obj;  
    }  
      
    /** 
     * 数据导入单入口 
     * @param string $file_or_date 数据文件,或者每日更新日期(格式:2014-08-23) 
     * @param string $driver 数据类型,不传的话,自动根据数据文件名称判断数据类型 
     * @param string $consoleOutput 是否把日志输出到终端屏幕 
     * @param string $default_file_year 默认年份,有些数据文件按月份命名,需要传入默认的年份,组合成数据的日期 
     * @param mixed $run_specific_driver 只导入指定的类型的数据,部分压缩数据包,里面包括多个数据文件 
     * @return mixed 返回导入行数 
     */  
    public static function import($file_or_date, $driver=NULL, $consoleOutput=true, $default_file_year=NULL, $run_specific_driver=NULL){  
        // auto detect driver & date from file name  
        if(!$driver){  
            if(is_dir($file_or_date)){  
                import(ORG.Util.File);  
                  
                $aFiles = File::getDirFiles($file_or_date, array(zip, rar));  
                  
                sort($aFiles, SORT_NATURAL);  
  
            }else{  
                $aFiles = array($file_or_date);  
            }  
              
            foreach($aFiles as $file){  
                $detect_info = self::guess_driver_from_file_name($file);  
                if(!$detect_info){  
                    return self::throw_exception("Cann‘t detect driver for file {$file}", SCRIPT_ERR_CONFIG, $file, __FILE__, __LINE__);  
                }  
                      
                $driver = $detect_info[driver];  
                $date = $detect_info[date];  
                      
                if(is_array($driver)){  
                    foreach($driver as $d){  
                        if(!$run_specific_driver || $run_specific_driver==$d){  
                            self::import(array(date=>$date, down=>$file), $d, $consoleOutput, $default_file_year);  
                        }  
                    }  
                }else{  
                    self::import(array(date=>$date, down=>$file), $driver, $consoleOutput, $default_file_year);  
                }  
            }  
              
            return;  
        }  
          
        $obj = self::factory($driver);  
        if(!$obj){  
            return self::throw_exception("Driver {$driver} not exists", SCRIPT_ERR_CONFIG, $driver, __FILE__, __LINE__);  
        }  
          
        if(is_array($file_or_date) || self::filter_date($file_or_date)){  
            $func = importUpdate;  
        }elseif(is_file($file_or_date)){  
            $func = importFile;  
        }elseif(is_dir($file_or_date)){  
            $func = importFolder;  
        }else{  
            return self::throw_exception("File or folder {$file_or_date} not exists", self::ERR_FILE_READ, $file_or_date, __FILE__, __LINE__);  
        }  
          
        $obj->consoleOutput($consoleOutput);  
        if($default_file_year){  
            $obj->default_file_year($default_file_year);  
        }  
          
        return $obj->$func($file_or_date);  
    }  
      
    /** 
     * 返回数据类型对应的字段定义 
     * @param string $driver 数据类型 
     * @param bool $isUpdate 是否为每日更新,历史数据和每日更新数据的表结构存在不一样的情况 
     * @return array 
     */  
    public static function getFields($driver, $isUpdate=false){  
        if(empty(self::$_fields_maps)){  
            self::$_fields_maps = require APP_ROOT_PATH . app/Web/Inc/stock_fields.inc.php;  
        }  
          
        if($isUpdate && isset(self::$_fields_maps[$driver]["UPDATE"])){  
            return self::$_fields_maps[$driver]["UPDATE"];  
        }else{  
            return isset(self::$_fields_maps[$driver]["IMPORT"])?self::$_fields_maps[$driver]["IMPORT"]:self::$_fields_maps[$driver];  
        }  
    }  
      
    /** 
     * 返回数据类型对应表名 
     * @param string $driver 数据类型 
     * @return string 
     */  
    public static function getTable($driver){  
        static $_SHSZ_TABLES = array(  
                self::SHSZ_5MIN => shsz_5min,  
                self::SHSZ_5MIN_FORWARD => shsz_5min_forward,  
                self::SHSZ_BALANCE_SHEET => shsz_balance_sheet,  
                self::SHSZ_BLOCK => shsz_block,  
                self::SHSZ_CAPITAL_STOCK => shsz_capital_stock,  
                self::SHSZ_CASHFLOW_STATEMENT => shsz_cashflow_statement,  
                self::SHSZ_DAY => shsz_day,  
                self::SHSZ_DAY_FORWARD => shsz_day_forward,  
                self::SHSZ_FINANCE => shsz_finance,  
                self::SHSZ_FINANCE37 => shsz_finance37,  
                self::SHSZ_FINANCIAL_ANALYSIS_INDEX => shsz_financial_analysis_index,  
                self::SHSZ_INCOME_STATEMENT => shsz_income_statement,  
                self::SHSZ_SHAREHOLDER => shsz_shareholder,  
                self::SHSZ_SPLIT => shsz_split,  
                self::SHSZ_TRADABLE_SHAREHOLDER => shsz_tradable_shareholder,  
                  
                self::HK_FINANCE => hk_finance,  
                self::HK_INDUSTRY => hk_industry,  
                self::HK_SPLIT => hk_split,  
                self::HK_5MIN => hk_5min,  
                self::HK_5MIN_FORWARD => hk_5min_forward,  
                self::HK_DAY => hk_day,  
                self::HK_DAY_FORWARD => hk_day_forward,  
  
        );  
          
        return $_SHSZ_TABLES[$driver];  
    }  
      
    /** 
     * 返回对应数据类型的归档天数 
     * @param string $driver 
     * @return number|false 
     */  
    public static function getArchiveDays($driver){  
        switch($driver){  
            case self::SHSZ_DAY:  
            case self::SHSZ_DAY_FORWARD:  
            case self::HK_DAY:  
            case self::HK_DAY_FORWARD:  
                $day = C(STOCK_ARCHIVE_DAY);  
                return $day;  
                break;  
                  
            case self::SHSZ_5MIN:  
            case self::SHSZ_5MIN_FORWARD:  
            case self::HK_5MIN:  
            case self::HK_5MIN_FORWARD:  
                $day = C(STOCK_ARCHIVE_5MIN);  
                return $day;  
                break;  
                  
            default:  
                return false;  
        }  
    }  
      
    /** 
     * 导入每日更新 
     * @param string $date 日期,格式如:2014-08-23 
     * @param string $extension 每日更新数据文件后缀名 
     * @return boolean 
     */  
    public function importUpdate($date, $extension=csv){  
        return $this->_importUpdate($date, $extension);  
    }  
      
    /** 
     * 导入文件夹内数据 
     * @param string $folder 文件夹 
     * @param string $extension 数据文件后缀名 
     */  
    public function importFolder($folder, $extension=csv){  
        return $this->_importFolder($folder, $extension);  
    }  
      
    /** 
     * 设置默认年份 
     * @param string $year 
     */  
    public function default_file_year($year=NULL){  
        if(is_null($year)){  
            return $this->_default_file_year;  
        }else{  
            $this->_default_file_year = $year;  
        }  
    }  
      
    /** 
     * 设置SQL模式 
     * @param string $strict 是否为严格模式,可以传true/false/模式名称 
     */  
    public function sql_mode($strict=true){  
        if($strict){  
            $this->_sql_mode = $strict===true?TRADITIONAL:$strict;  
        }else{  
            $this->_sql_mode = ‘‘;  
        }  
          
        $this->_VM()->query(SET sql_mode = " . $this->_sql_mode . ");  
    }  
  
    /** 
     * 手机号码过滤 
     * @param string $v 
     * @return string 
     */  
    public static function filter_mobile($v){  
        if(preg_match(/0?(1[0-9]{10})/, $v, $m)){  
            return $m[1];  
        }else{  
            return ‘‘;  
        }  
    }  
      
    /** 
     * 单位万转换 
     * @param number $v 
     * @return number 
     */  
    public static function filter_tenthousands($v){  
        //return $v?$v*10000:0;  
        return $v?bcmul($v, 10000, 0):0;  
    }  
      
    /** 
     * 单位前转换 
     * @param number $v 
     * @return number 
     */  
    public static function filter_thousand($v){  
        //return $v?$v*1000:0;  
        return $v?bcmul($v, 1000, 0):0;  
    }  
      
    /** 
     * 转换为整型 
     * @param number $v 
     * @return number 
     */  
    public static function filter_intval($v){  
        return bcadd($v, 0, 0);  
    }  
      
    /** 
     * 日期转换 
     * @param string $v 
     * @return string 
     */  
    public static function filter_date($v){  
        if(!$v){  
            return false;  
        }  
  
        if(preg_match(/^([0-9]{4})([0-9]{2})([0-9]{2})$/, $v, $m)  
        || preg_match(/^([0-9]{4})[\/|\-]{1}([0-9]{1,2})[\/|\-]{1}([0-9]{1,2})$/, $v, $m)  
        || preg_match(/^([0-9]{4})[\/|\-]{1}([0-9]{1,2})[\/|\-]{1}([0-9]{1,2})\s+[0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2}$/, $v, $m)  
        ){  
            return $m[1] . - . $m[2] . - . $m[3];  
        }else{  
            // 尝试 Converts a Gregorian date to Julian Day Count  
            return  (is_numeric ($v) && ($v=self::filter_convert_datetime($v)))?$v:false;  
        }  
    }  
      
    /** 
     * 日期时间转换 
     * @param string $v 
     * @return string 
     */  
    public static function filter_datetime($v){  
        if(preg_match(/^([0-9]{4})[\/|\-]{1}([0-9]{1,2})[\/|\-]{1}([0-9]{1,2})\s+([0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2})$/, $v, $m)  
        ){  
            return $m[1] . - . $m[2] . - . $m[3] .   . $m[4];  
        }else{  
            return false;  
        }  
    }  
      
    public static function filter_stock_code($v){  
        if(preg_match(/^(SH|SZ)[0-9]{6}$/i, $v) || preg_match(/^HK[0-9]{5}$/i, $v)){  
            return strtoupper($v);  
        }elseif(preg_match(/^HK([0-9]{4})$/i, $v, $m)){  
            return strtoupper(HK0 . $m[1]);  
        }else{  
            return false;  
        }  
    }  
  
    protected function _batch_exec_sqls($sql, $delimiter=;){  
        $oVirtualModel = $this->_VM();  
      
        if(is_string($sql)){  
            $aSQLs = SQLKit::parse_sqls($sql);  
        }else{  
            $aSQLs = $sql;  
        }  
      
        $total = 0;  
        $succs = 0;  
        $fails = 0;  
      
        $this->_log("Start batch execute SQLs");  
      
        foreach ($aSQLs as $sql){  
            if(!$sql) continue;  
            $this->_log("Query: " . $sql);  
            $result = $oVirtualModel->execute($sql);  
            $this->_log("Result is " . $result?succ:fail:  . $oVirtualModel->getDbError());  
      
            if($result){  
                $this->_setError("导入失败:" . $oVirtualModel->getDbError());  
            }  
      
            $total++;  
            if($result){  
                $succs++;  
            }else{  
                $fails++;  
            }  
        }  
      
        $this->_log("Finished!");  
        $this->_log("Total executed: " . $total . ", succ: " . $succs . ", fail: " . $fails);  
    }  
      
    protected function _VM(){  
        if(!$this->_oVirtualModel){  
            import(COM.GZNC.VirtualModel);  
            $this->_oVirtualModel = new VirtualModel();  
        }  
      
        return $this->_oVirtualModel;  
    }  
      
    /** 
     * 使用mysqli连接数据库 
     * @return object 
     */  
    protected function _mysqli(){  
        static $mysqli = NULL;  
          
        if($mysqli){  
            return $mysqli;  
        }  
          
        // 写入数据库  
        $mysqli = new mysqli(p: . C(DB_HOST), C(DB_USER), C(DB_PWD), C(DB_NAME), C(DB_PORT));  
          
        /* 
         * This is the "official" OO way to do it, 
        * BUT $connect_error was broken until PHP 5.2.9 and 5.3.0. 
        */  
        if ($mysqli->connect_error) {  
            return $this->_trigger_error(Connect DB Error ( . $mysqli->connect_errno . )   
                    . $mysqli->connect_error  
                    , self::ERR_DB_CONNECT  
                    , NULL  
                    , __FILE__  
                    , __LINE__  
            );  
        }  
          
        /* change character set to utf8 */  
        if (!$mysqli->set_charset("utf8")) {  
            return $this->_trigger_error(sprintf("Error loading character set utf8: %s\n", $mysqli->error)  
                    , self::ERR_DB_QUERY  
                    , NULL  
                    , __FILE__  
                    , __LINE__  
            );  
        }  
          
        return $mysqli;  
    }  
      
  
    /** 
     * 保存行数据到数据库 
     * @param string $table 表明 
     * @param string|array $key 表主键 
     * @param string $file 数据文件名称 
     * @param int $line 当前行值,如1,2,3,4 
     * @param array $fieldValues 字段回调函数处理过后的列值 
     * @param array $rowValues 原始列植 
     * @param array $options 选项设置 
     * @param bool $replace 是否用替换方式写入数据数据库 
     * @return string 
     */  
    public function _cb_row_save($table, $key, $file, $line, $fieldValues, $rowValues, $options=NULL, $replace=false){  
        $oVirtualModel = $this->_VM();  
  
        if(!$replace){  
            $exist_row = false;  
            if($key){  
                $where = is_array($key)?$key:array($key => $fieldValues[$key]);  
                      
                //----------------------  
                // 注意:  
                // 2014-10-12 zhongyw  
                // Cli db->escapeString() 内的mysql_escape_string方法导入大数据时存在内存泄漏情况  
                // 改为自行生成查询SQL  
                //$exist_row = $oVirtualModel->table($table)->where($where)->find();  
                //--------------------------  
                $exist_sql = "SELECT";  
                if(is_array($key)){  
                    $exist_sql .= " " . implode(, , array_keys($key));  
                }else{  
                    $exist_sql .= " `" . $key . "`";  
                }  
              
                if(!empty($options[checkUpdateDate])){  
                    $exist_sql .= ", update_date";  
                }  
                      
                $exist_sql .= " FROM `" . $table . "`";  
                $exist_sql .= " WHERE " . SQLKit::where_expr($where);  
                $exist_sql .= " LIMIT 1";  
                      
                $exist_result = $oVirtualModel->query($exist_sql);  
                      
                $exist_row = !empty($exist_result) && is_array($exist_result)?$exist_result[0]:false;  
            }  
              
            if(empty($exist_row)){  
                if(!empty($options[_addFieldValues]) && is_array($options[_addFieldValues])){  
                    $fieldValues = array_merge($fieldValues, $options[_addFieldValues]);  
                }  
                      
                $sql = SQLKit::insert_stmt($table, $fieldValues);  
              
                $operation = "Insert";  
            }else{  
                if(!empty($options[_updateFieldValues]) && is_array($options[_updateFieldValues])){  
                    $fieldValues = array_merge($fieldValues, $options[_updateFieldValues]);  
                }  
                      
                if(!empty($options[checkUpdateDate])  
                && !empty($exist_row[update_date]) && !empty($fieldValues[update_date])  
                && str_replace(array(-, /), ‘‘, $exist_row[update_date]) > str_replace(array(-, /), ‘‘, $fieldValues[update_date])  
                ){  
                    $this->_log("Exist record date(" . $exist_row[update_date] . ") is newer than update line:" . $line . " date (" . $fieldValues[update_date] . ")", LOG::WARN);  
                    $this->_log("Skip Update");  
                    return true;  
                }  
                      
                $sql = SQLKit::update_stmt($table, $fieldValues, $where);  
                $operation = "Update";  
            }  
        }else{  
            if(!empty($options[_addFieldValues]) && is_array($options[_addFieldValues])){  
                $fieldValues = array_merge($fieldValues, $options[_addFieldValues]);  
            }  
              
            if(!empty($options[_updateFieldValues]) && is_array($options[_updateFieldValues])){  
                $fieldValues = array_merge($fieldValues, $options[_updateFieldValues]);  
            }  
                  
            $sql = SQLKit::replace_stmt($table, $fieldValues);  
                  
            $operation = "Replace";  
        }  
  
          
        $this->_last_sql = $sql;  
          
        if (! empty ( $options [instantWrite] ) && !empty($sql)) {  
          
            $log_content = "Line {$line}" . ($this->_log_sql?": $sql":"");  
              
            $dbError = NULL;  
              
            try {  
                $result = $oVirtualModel->execute ( $sql );  
            } catch ( Exception $e ) {  
                $result = false;  
                $dbError = $e->getMessage ();  
            }  
              
            // $result可能=0,当update同样内容数据的时候,必须要通过判断===false  
            if (false === $result) {  
                if (! $dbError) {  
                    $dbError = $oVirtualModel->getDbError ();  
                }  
                  
                $this->_log( $log_content . ": $sql");  
                $this->_log($operation . " FAIL: $dbError" );  
                  
                return $this->_trigger_error ( "Line {$line} importing SQL execute Failed: " . $dbError  
                        , self::ERR_SQL_EXECUTE  
                        , array (  
                                line => $line,  
                                sql => $sql   
                        )  
                        , __FILE__, __LINE__   
                );  
            } else {  
                $this->_log ( $log_content . ": " . $operation . " SUCC" );  
                return true;  
            }  
        } else {  
            return $sql;  
        }  
    }  
      
      
    /** 
     * 写入日志 
     * @param string $message 日志消息 
     * @param string $level 日志等级 
     * @return boolean 
     */  
    protected function _log($message, $level=LOG::INFO){  
        if($this->_log){  
            if (is_callable ( $this->_log )) {  
                static $aLogLevelMaps = array (  
                        LOG::EMERG => 0,  
                        LOG::ALERT => 1,  
                        LOG::CRIT => 2,  
                        LOG::ERR => 3,  
                        LOG::WARN => 4,  
                        LOG::NOTICE => 5,  
                        LOG::INFO => 6,  
                        LOG::DEBUG => 7   
                );  
                  
                if ($this->_log && $aLogLevelMaps [$level] > $aLogLevelMaps [$this->_logLevel]) {  
                    return false;  
                }  
                  
                return Runder::run_callback ( $this->_log, array (  
                        $message,  
                        $level   
                ) );  
            }else{  
                return parent::_log($message, $level, $this->_logLevel);  
            }  
        }else{  
            return false;  
        }  
    }  
      
    /** 
     * xls文件转为csv 
     * @param string $xls_file 源xls文件 
     * @param string $csv_file 目标csv文件 
     * @param string $overwrite 是否覆盖 
     * @return string 返回目标csv文件名称 
     */  
    protected function _convertXls2Csv($xls_file, $csv_file=NULL, $overwrite=false){  
        $this->_log("Try convert xls to csv: $xls_file ");  
          
        if(!$csv_file){  
            $csv_file = (!strcasecmp(xls, File::getExtension($xls_file))?substr($xls_file, 0, strrpos($xls_file, .)):$xls_file) . .csv;  
        }  
          
        if(!$overwrite && self::file_exists($csv_file)){  
            $this->_log("CSV file already exists");  
            $this->_log("Skip converting");  
            return $csv_file;  
        }  
          
        $bin_maps = C(BIN_MAPS);  
        $oCommand = new Command($bin_maps);  
  
          
        $convert_xls_file = self::convert2filesystemname($xls_file);  
        $to_csv_file = self::convert2filesystemname($csv_file);  
           
        /* 
        $this->_log("\$convert_xls_file: ". $convert_xls_file); 
        $this->_log("\$to_csv_file: ". $to_csv_file); 
        $this->_log("\$convert_xls_file exist ". (file_exists($convert_xls_file)?‘Yes‘:‘No‘)); 
        */  
  
        if(!empty($bin_maps[libxls2csv])){  
            $cmd_status = $oCommand->libxls2csv($convert_xls_file, $to_csv_file, GBK, "", ",");  
        }else{  
            $cmd_status = $oCommand->xls2csv($convert_xls_file, $to_csv_file, cp936, cp936);  
        }  
          
        if(1==$cmd_status){  
            return $this->_trigger_error("Cann‘t convert xls to csv file: " . $oCommand->cmdOutput("\n")  
                    , self::ERR_OTHER_MISC  
                    , array(driver=>$this->_driver, xls_file => $xls_file, csv_file=> $csv_file)  
                    , __FILE__  
                    , __LINE__  
            );  
        }else{  
            $this->_log($oCommand->cmdOutput("\n"));  
            $this->_log("Convert Succ!");  
            $this->_log("CSV file is " . $csv_file);  
            return $csv_file;  
        }  
    }  
      
    /** 
     * 解压每日下载文件 
     * @param string $down_file 下载文件 
     * @param string $update_file 解压目标文件 
     * @return boolean 
     */  
    protected function _decompressDownFile($down_file, $update_file=null){  
        $this->_log("Down file is {$down_file}");  
          
        if(!self::file_exists($down_file)){  
            return $this->_trigger_error("Down file not exists!"  
                    , self::ERR_FILE_READ  
                    , array(driver=>$this->_driver, down_file => $down_file)  
                    , __FILE__  
                    , __LINE__  
            );  
        }  
          
        $down_fext = File::getExtension($down_file);  
        switch(strtolower($down_fext)){  
            case csv:  
            case xls:  
                // Copy to update folder  
                $this->_log("Try copy to update folder as file: " . $update_file);  
  
                if(!copy($down_file, $update_file)){  
                    return $this->_trigger_error("Cann‘t copy down file to update file!"  
                            , self::ERR_OTHER_MISC  
                            , array(driver=>$this->_driver, down_file => $down_file, update_file=> $update_file)  
                            , __FILE__  
                            , __LINE__  
                    );  
                }  
  
                $this->_log("Copy Succ!");  
                  
                break;  
              
            case zip:  
            case rar:  
                $this->_log("Try decompress down file");  
                  
                $update_dir = dirname($update_file);  
                  
                $oCommand = new Command(C(BIN_MAPS));  
                $cmd_status = $oCommand->decompress($down_file, $update_dir);  
                if(1==$cmd_status){  
                    return $this->_trigger_error("Cann‘t decompress down file: " . $oCommand->cmdOutput("\n")  
                            , self::ERR_OTHER_MISC  
                            , array(driver=>$this->_driver, down_file => $down_file, update_file=> $update_file)  
                            , __FILE__  
                            , __LINE__  
                    );  
                }  
                  
                $this->_log($oCommand->cmdOutput("\n"));  
                  
                $this->_log("Decompress Succ!");  
                $this->_log("Saved into update directory: {$update_dir}");  
                  
                break;  
                  
            default:  
                return $this->_trigger_error("Unknown file type: " . $down_fext  
                        , self::ERR_OTHER_MISC  
                        , array(driver=>$this->_driver, down_file => $down_file, update_file=> $update_file)  
                        , __FILE__  
                        , __LINE__  
                );  
        }  
          
        return true;  
    }  
      
  
    /** 
     * 导入文件夹 
     * @param string $folder 文件夹,完整路径 
     * @param string $extension 文件扩展名 
     * @param string $namepattern 文件名匹配正则 
     */  
    protected function _importFolder($folder, $extension=csv, $namepattern=NULL){  
        import(ORG.Util.Debug);  
      
        $debug_start_mark = start_import_folder;  
        $debug_end_mark = end_import_folder;  
      
        Debug::mark($debug_start_mark);  
      
        $this->_log("+++++++++++++++++++++++++++++++++++++");  
        $this->_log("START IMPORT FOLDER");  
        $this->_log("Folder {$folder}");  
      
        import(ORG.Util.File);  
      
        $aFiles = File::getDirFiles($folder, $extension);  
          
        sort($aFiles, SORT_NATURAL);  
  
        foreach($aFiles as $file){  
            if(!$namepattern || preg_match($namepattern, $file)){  
                $this->importFile($file);  
            }  
        }  
      
        Debug::mark($debug_end_mark);  
      
        $performance = "Cost time " . Debug::useTime($debug_start_mark,$debug_end_mark).s;  
        $performance .= ", used memory " . Debug::useMemory($debug_start_mark,$debug_end_mark).kb;  
        $performance .= ", peak memory " . Debug::getMemPeak($debug_start_mark, $debug_end_mark).kb;  
        $this->_log( $performance );  
      
        $this->_log("END IMPORT FOLDER.[$folder]");  
        $this->_log("+++++++++++++++++++++++++++++++++++++");  
    }  
      
    /** 
     * 导入数据文件 
     * @param string $file 数据文件 
     * @param array $fields 数据字段定义 
     * @param array $options 选项 
     * @param string $file_content 数据内容,传的话不再从$file读取,实时数据更新时有用 
     * @throws Exception 
     * @return mixed 
     */  
    protected function _importFile($file, $fields, $options=array(  
            titleRow => 1,  //  标题行数  
            dataRow => 2, // 数据开始行数  
            instantWrite => true, // 实时写  
            rowCallback => _cb_row,  
            fieldCallback => _cb_field,  
              
            fromEncoding => GBK,  
            toEncoding => UTF-8,  
    ), $file_content=NULL){  
          
        $this->_begin_dblog($file);  
          
        import(ORG.Util.Debug);  
      
        $debug_start_mark = start_import_file;  
        $debug_end_mark = end_import_file;  
      
        Debug::mark($debug_start_mark);  
      
        $this->_log("----------------------------");  
        $this->_log("START IMPORT FILE");  
        $this->_log("File {$file}");  
      
        $this->_stats[total] = 0;  
        $this->_stats[succ] = 0;  
        $this->_stats[fail] = array();  
  
        $this->sql_mode(true);  
        try {  
            $sqls = $this->_import ( self::convert2filesystemname ( $file ), $fields, $options, $file_content);  
              
            // S4Web::debug_log($sqls);  
              
            if (! $sqls) {  
                $error = $this->getError ();  
                  
                $this->_log ( "Import Failed: " . $error, LOG::ERR );  
                $this->_end_dblog ( false, $error );  
                  
                // 监听处理  
                $this->_callListener(self::LISTENER_IMPORT_RESULT, array($file, $error, false));  
                  
                return false;  
            }  
        } catch ( Exception $e ) {  
            $this->_end_dblog ( false, $e);  
              
            // 监听处理  
            $this->_callListener(self::LISTENER_IMPORT_RESULT, array($file, $e, false));  
              
            throw  $e;  
        }  
      
        //$this->_batch_exec_sqls($sqls);  
      
        $message = "Total found " . $this->_stats[total] .  records;  
        $message .= ", Succ " . ($this->_stats[succ]?$this->_stats[succ]:"<B COLOR=RED>" . $this->_stats[succ] . "</B>");  
        $message .= ", Fail " . count($this->_stats[fail]);  
        $message .= $this->_stats[fail]?" Lines: " . implode(,, $this->_stats[fail]):‘‘;  
        $message .= ".";  
        //$this->_setMessage($message);  
      
        $this->_log($message);  
      
        Debug::mark($debug_end_mark);  
          
        $this->_stats[costsecs] = Debug::useTime($debug_start_mark,$debug_end_mark, 3);  
        $this->_stats[usedmemory] = str_replace(,, ‘‘, Debug::useMemory($debug_start_mark,$debug_end_mark));  
        $this->_stats[peakmemory] = str_replace(,, ‘‘, Debug::getMemPeak($debug_start_mark,$debug_end_mark));  
      
        $performance = "Cost time " . Debug::useTime($debug_start_mark,$debug_end_mark).s;  
        $performance .= ", used memory " . Debug::useMemory($debug_start_mark,$debug_end_mark).kb;  
        $performance .= ", peak memory " . Debug::getMemPeak($debug_start_mark, $debug_end_mark).kb;  
        $this->_log( $performance );  
      
        $this->_log("END IMPORT FILE.[$file]");  
        $this->_log("----------------------------");  
  
        $this->_end_dblog (true, $message . "\n" . $performance);  
          
        // 监听处理  
        $this->_callListener(self::LISTENER_IMPORT_RESULT, array($file, $message, $this->_stats));  
      
        return $sqls;  
    }  
      
    /** 
     * 导入每日更新 
     * @param string $date 日期 
     * @param string $extension 文件后缀名 
     * @return boolean 
     */  
    protected function _importUpdate($date, $extension=csv){  
        import(ORG.Util.Debug);  
      
        $debug_start_mark = start_import_update;  
        $debug_end_mark = end_import_update;  
      
        Debug::mark($debug_start_mark);  
      
        $this->_log("=======================================");  
        $this->_log("START IMPORT UPDATE");  
          
        $update_dir = $this->_get_update_dir($date, true);  
          
        if(is_array($date)){  
            $update_file = $date[update];  
            $down_file = $date[down];  
            $date = $date[date];  
        }elseif(self::filter_date($date)){  
            $down_file = $this->_get_down_file($date);  
              
            // 沪深财务四张表先解压再匹配名称  
            switch ($this->_driver){  
                case self::SHSZ_INCOME_STATEMENT:  
                case self::SHSZ_BALANCE_SHEET:  
                case self::SHSZ_CASHFLOW_STATEMENT:  
                case self::SHSZ_FINANCIAL_ANALYSIS_INDEX:  
                    $this->_decompressDownFile($down_file, $update_dir . /update_file);  
                    break;  
            }  
              
            $update_file = $this->_get_update_file($date);  
              
        }elseif(is_file($date)){  
            $down_file = $date;  
            $guess_info = self::guess_driver_from_file_name($down_file);  
            $date = $guess_info[date];  
        }else{  
            $this->_log("Import failed: Unknown date or file for driver " . $this->_driver . ": {$date}");  
            return false;  
        }  
          
        if(!$date || !self::filter_date($date)){  
            $this->_log("Import failed: Unknown date for driver " . $this->_driver . ": {$date}");  
            return false;  
        }  
          
  
        if(!$down_file){  
            $down_file = $this->_get_down_file($date);  
        }  
          
        if(!$update_file){  
            $update_file = $this->_get_update_file($date);  
        }  
          
        if(!$update_file){  
            $this->_log("Import failed: Cann‘t get update file for driver " . $this->_driver . " on date {$date}");  
            return false;  
        }elseif(is_string($update_file)){  
            $update_files = array($update_file);  
        }else{  
            $update_files = $update_file;  
        }  
          
  
        // set update importing  
        $this->_is_update = true;  
        $this->_update_date = $date;  
          
        $this->_log("Date {$date}");  
        $this->_log("Down File: " . $down_file);  
          
        foreach($update_files as $update_file){  
            $this->_log("Update File: " . $update_file);  
            $this->_log("Check if Update file exists");  
              
            $this->_update_file = $update_file;  
  
            // Check update file existence, and Try to decompress down file  
            if(!self::file_exists($update_file)){  
                if((!$this->_decompressDownFile($down_file, $update_file) || !self::file_exists($update_file))){  
                    $this->_log("Import Failed: Update file not exists, Cann‘t decompress from down file!");  
                    return false;  
                }  
            }else{  
                $this->_log("Update file already exists");  
            }  
              
            $update_fext = File::getExtension($update_file);  
            if(!strcasecmp(xls, $update_fext) && !strcasecmp(csv, $extension)   
            && (!($update_file = $this->_convertXls2Csv($update_file)) || !self::file_exists($update_file))){  
                $this->_log("Import Failed: Update file not exists, Cann‘t convert file type from xls to csv!");  
                return false;  
            }  
                  
            $this->importFile($update_file);  
        }  
          
        Debug::mark($debug_end_mark);  
      
        $performance = "Cost time " . Debug::useTime($debug_start_mark,$debug_end_mark).s;  
        $performance .= ", used memory " . Debug::useMemory($debug_start_mark,$debug_end_mark).kb;  
        $performance .= ", peak memory " . Debug::getMemPeak($debug_start_mark, $debug_end_mark).kb;  
        $this->_log( $performance );  
      
        $this->_log("END IMPORT UPDATE.");  
        $this->_log("=======================================");  
          
        return true;  
    }  
      
      
    /** 
     * 根据数据类型和日期,返回自动下载文件名称 
     *  
     * @param string $driver 数据类型 
     * @param string $date 日期 
     * @return false|string 
     */  
    public static function guess_down_file_name($driver, $date){  
        if(!is_numeric($date)){  
            $timestamp = strtotime($date);  
        }else{  
            $timestamp = $date;  
        }  
          
        if(!$timestamp){  
            return false;  
        }  
          
        $shortdate = date(md, $timestamp);  
        $date = date(Ymd, $timestamp);  
          
      
          
        switch ($driver) {  
            case self::SHSZ_FINANCE :  
                // wss0929fin.zip  
                $name = wss . $shortdate . fin.zip;  
                break;  
                  
            case self::SHSZ_BLOCK :  
                // wss0929blk.zip  
                $name = wss . $shortdate . blk.zip;  
                break;  
                  
            case self::SHSZ_BALANCE_SHEET :  
            case self::SHSZ_CASHFLOW_STATEMENT :  
            case self::SHSZ_INCOME_STATEMENT :  
            case self::SHSZ_FINANCIAL_ANALYSIS_INDEX :  
                // ws0929rpt.zip  
                $name = ws . $shortdate . rpt.zip;  
                break;  
                  
            case self::SHSZ_SHAREHOLDER :  
            case self::SHSZ_TRADABLE_SHAREHOLDER:  
                // wsSHSZ_Shareholders_20140929.rar  
                $name = wsSHSZ_Shareholders_ . $date . .rar;  
                break;  
                  
            case self::SHSZ_CAPITAL_STOCK :  
                // wsSHSZ_CapitalStocks_20140930_csv.zip  
                $name = wsSHSZ_CapitalStocks_ . $date . _csv.zip;  
                break;  
  
            /*   
            case self::SHSZ_DAY : 
                // wss0929e.zip 
                //$name = ‘wss‘ . $shortdate . ‘e.zip‘; 
                break; 
                 
            case self::SHSZ_5MIN : 
                // wss0929e5.zip 
                $name = ‘wss‘ . $shortdate . ‘e5.zip‘; 
                break; 
            */  
  
            case self::SHSZ_SPLIT:  
            case self::SHSZ_DAY:  
            case self::SHSZ_DAY_FORWARD:  
            case self::SHSZ_5MIN:  
            case self::SHSZ_5MIN_FORWARD:  
                // wstock_SHSZ_Day_5Min_SPLIT_20140930.zip  
                $name = "wstock_SHSZ_Day_5Min_SPLIT_{$date}.zip";  
                break;  
                  
            case self::HK_FINANCE :  
                // wsHK_finance_20141114.zip  
                $name = wsHK_finance_ . $date . .zip;  
                break;  
                  
            case self::HK_INDUSTRY :  
                // wsHK_Industry_20141114.zip  
                $name = wsHK_Industry_ . $date . .zip;  
                break;  
  
            case self::HK_SPLIT:  
            case self::HK_DAY:  
            case self::HK_DAY_FORWARD:  
            case self::HK_5MIN:  
            case self::HK_5MIN_FORWARD:  
                // wstock_HK_Day_5Min_SPLIT_20140930.zip  
                $name = "wstock_HK_Day_5Min_SPLIT_{$date}.zip";  
                break;  
  
            default:  
                return false;  
        }  
          
        return $name;  
    }  
      
    /** 
     * 根据数据类型和日期,返回自动下载解压后文件名称 
     * 
     * @param string $driver 数据类型 
     * @param string $date 日期 
     * @return false|string|array 
     */  
    public static function guess_update_file_name($driver, $date, $updatedir=NULL){  
        if(!is_numeric($date)){  
            $timestamp = strtotime($date);  
        }else{  
            $timestamp = $date;  
        }  
          
        if(!$timestamp){  
            return false;  
        }  
          
        $shortdate = date(md, $timestamp);  
        $date = date(Ymd, $timestamp);  
          
        switch ($driver) {  
            case self::SHSZ_FINANCE :  
                // wss0930finance.csv  
                $name = wss . $shortdate . finance.csv;  
                break;  
          
            case self::SHSZ_BLOCK :  
                // wsSHSZ_Block_20140930.csv  
                $name = wsSHSZ_Block_ . $date . .csv;  
                break;  
          
            // @todo: 需要依据一定规则自动判断按季变化的文件名称  
            case self::SHSZ_BALANCE_SHEET :  
                // SHSZ_2013Q2-2014Q2_资产负债表.xls  
                //$name = "SHSZ_2013Q3-2014Q3_资产负债表.xls";  
                $namepattern = ^SHSZ_[0-9A-Z\-]+_资产负债表\.xls$;  
                $name = self::_match_update_file_name($updatedir, $namepattern);  
                break;  
            case self::SHSZ_CASHFLOW_STATEMENT :  
                // SHSZ_2013Q2-2014Q2_现金流量表.xls  
                //$name = "SHSZ_2013Q3-2014Q3_现金流量表.xls";  
                $namepattern = ^SHSZ_[0-9A-Z\-]+_现金流量表\.xls$;  
                $name = self::_match_update_file_name($updatedir, $namepattern);  
                break;  
            case self::SHSZ_INCOME_STATEMENT :  
                // SHSZ_2013Q2-2014Q2_利润表.xls  
                //$name = "SHSZ_2013Q3-2014Q3_利润表.xls";  
                $namepattern = ^SHSZ_[0-9A-Z\-]+_利润表\.xls$;  
                $name = self::_match_update_file_name($updatedir, $namepattern);  
                break;  
            case self::SHSZ_FINANCIAL_ANALYSIS_INDEX :  
                // SHSZ_2013Q2-2014Q2_相关91项分析指标.xls  
                //$name = "SHSZ_2013Q3-2014Q3_相关91项分析指标.xls";  
                $namepattern = ^SHSZ_[0-9A-Z\-]+_相关91项分析指标\.xls$;  
                $name = self::_match_update_file_name($updatedir, $namepattern);  
                break;  
          
            case self::SHSZ_SHAREHOLDER :  
                // SHSZ_Shareholders_2010Q3-20140929.xls  
                $name = "SHSZ_Shareholders_2010Q3-{$date}.xls";  
                break;  
                  
            case self::SHSZ_TRADABLE_SHAREHOLDER :  
                // SHSZ_TradableShareholders_2010Q3-20140929.xls  
                $name = "SHSZ_TradableShareholders_2010Q3-{$date}.xls";  
                break;  
          
            case self::SHSZ_CAPITAL_STOCK :  
                // SZ_CapitalStocks_1991-20140929.csv  
                // SH_CapitalStocks_1990-20140929.csv  
                $name = array(  
                    "SZ_CapitalStocks_1991-{$date}.csv",  
                    "SH_CapitalStocks_1990-{$date}.csv",  
                );  
                break;  
                  
            /* 
             * case self::SHSZ_DAY : // wss20140929r.csv $name = "wss{$date}r.csv"; break; case self::SHSZ_5MIN : // wss0929f.csv $name = "wss{$shortdate}f.csv"; break; 
             */  
                  
            case self::SHSZ_SPLIT:  
                // wstock_SHSZ_20141019_SPLITs.csv  
                $name = "wstock_SHSZ_{$date}_SPLITs.csv";  
                break;  
                  
            case self::SHSZ_DAY :  
                // wstock_SHSZ_20140930_Day.csv  
                $name = "wstock_SHSZ_{$date}_Day.csv";  
                break;  
              
            case self::SHSZ_DAY_FORWARD :  
                // wstock_SHSZ_20140930_Day_Forward.csv  
                $name = "wstock_SHSZ_{$date}_Day_Forward.csv";  
                break;  
              
            case self::SHSZ_5MIN :  
                // wstock_SHSZ_20140930_5Min.csv  
                $name = "wstock_SHSZ_{$date}_5Min.csv";  
                break;  
              
            case self::SHSZ_5MIN_FORWARD :  
                // wstock_SHSZ_20140930_5Min_Forward.csv  
                $name = "wstock_SHSZ_{$date}_5Min_Forward.csv";  
                break;  
                  
            case self::HK_FINANCE :  
                // wsHK_finance_20141114.csv  
                $name = wsHK_finance_ . $date . .csv;  
                break;  
                  
            case self::HK_INDUSTRY :  
                // wsHK_Industry_20141114.xls  
                $name = wsHK_Industry_ . $date . .xls;  
                break;  
                  
            case self::HK_SPLIT:  
                // wstock_HK_20141019_SPLITs.csv  
                $name = "wstock_HK_{$date}_SPLITs.csv";  
                break;  
                  
            case self::HK_DAY :  
                // wstock_HK_20140930_Day.csv  
                $name = "wstock_HK_{$date}_Day.csv";  
                break;  
                  
            case self::HK_DAY_FORWARD :  
                // wstock_HK_20140930_Day_Forward.csv  
                $name = "wstock_HK_{$date}_Day_Forward.csv";  
                break;  
              
            case self::HK_5MIN :  
                // wstock_HK_20140930_5Min.csv  
                $name = "wstock_HK_{$date}_5Min.csv";  
                break;  
              
            case self::HK_5MIN_FORWARD :  
                // wstock_HK_20140930_5Min_Forward.csv  
                $name = "wstock_HK_{$date}_5Min_Forward.csv";  
                break;  
          
            default:  
                return false;  
        }  
          
        return $name;  
    }  
      
    protected static function _match_update_file_name($updatedir, $namepattern){  
        import(ORG.Util.File);  
        $aFiles = File::getDirFiles($updatedir);  
          
        import(ORG.Util.String);  
        $aFiles = String::autoCharset($aFiles);  
          
        // force set regular match encoding as UTF-8  
        mb_regex_encoding(UTF-8);  
          
        foreach($aFiles as $file){  
            $filename = basename($file);  
            if(mb_ereg($namepattern, $filename)){  
                return $filename;  
            }  
        }  
          
        return false;  
    }  
      
    /** 
     * 从文件名判断数据类型和日期 
     *  
     * @param string $file 文件名 
     * @return false|array 
     */  
    public static function guess_driver_from_file_name($file){  
  
        $pathinfo = pathinfo($file);  
        if(!$pathinfo || !($basename=$pathinfo[basename])){  
            return false;  
        }  
          
        // wss0929fin.zip  
        if(preg_match(/^wss([0-9]{4})fin\.zip$/, $basename, $m)){  
            $return = array(  
                    driver => self::SHSZ_FINANCE,  
                    date => date(Y) . $m[1],  
            );  
        }  
          
        // wss0929blk.zip  
        elseif(preg_match(/^wss([0-9]{4})blk\.zip$/, $basename, $m)){  
            $return = array(  
                    driver => self::SHSZ_BLOCK,  
                    date => date(Y) . $m[1],  
            );  
        }  
          
        // ws0929rpt.zip  
        elseif(preg_match(/^ws([0-9]{4})rpt\.zip$/, $basename, $m)){  
            $return = array(  
                    driver => array(  
                            self::SHSZ_BALANCE_SHEET,   
                            self::SHSZ_CASHFLOW_STATEMENT,   
                            self::SHSZ_INCOME_STATEMENT,  
                            self::SHSZ_FINANCIAL_ANALYSIS_INDEX  
                    ),  
                    date => date(Y) . $m[1],  
            );  
        }  
          
        // wsSHSZ_Shareholders_20140929.rar  
        elseif(preg_match(/^wsSHSZ_Shareholders_([0-9]{8})\.rar$/, $basename, $m)){  
            $return = array(  
                    driver => array(  
                            self::SHSZ_SHAREHOLDER,  
                            self::SHSZ_TRADABLE_SHAREHOLDER,  
                    ),  
                    date => $m[1],  
            );  
        }  
          
        // wsSHSZ_CapitalStocks_20140929_csv.zip  
        elseif(preg_match(/^wsSHSZ_CapitalStocks_([0-9]{8})_csv\.zip$/, $basename, $m)){  
            $return = array(  
                    driver =>self::SHSZ_CAPITAL_STOCK,  
                    date => $m[1],  
            );  
        }  
          
        // wss0929e.zip  
        elseif(preg_match(/^wss([0-9]{4})e\.zip$/, $basename, $m)){  
            $return = array(  
                    driver => self::SHSZ_DAY,  
                    date => date(Y) . $m[1],  
            );  
        }  
          
        // wss0929e5.zip  
        elseif(preg_match(/^wss([0-9]{4})e5\.zip$/, $basename, $m)){  
            $return = array(  
                    driver => self::SHSZ_5MIN,  
                    date => date(Y) . $m[1],  
            );  
        }  
          
        // wstock_SHSZ_Day_5Min_20140930.zip  
        elseif(preg_match(/^wstock_SHSZ_Day_5Min_([0-9]{8})\.zip$/, $basename, $m)){  
            $return = array(  
                    driver => array(  
                            self::SHSZ_SPLIT,  
                            self::SHSZ_DAY,  
                            self::SHSZ_DAY_FORWARD,  
                            self::SHSZ_5MIN,  
                            self::SHSZ_5MIN_FORWARD,  
                    ),  
                    date => $m[1],  
            );  
        }  
          
        // wsHK_finance_20141114.zip  
        elseif(preg_match(/^wsHK_finance_([0-9]{8})\.zip$/, $basename, $m)){  
            $return = array(  
                    driver => self::HK_FINANCE,  
                    date => $m[1],  
            );  
        }  
          
        // wsHK_Industry_20141114.zip  
        elseif(preg_match(/^wsHK_Industry_([0-9]{8})\.zip$/, $basename, $m)){  
            $return = array(  
                    driver => self::HK_INDUSTRY,  
                    date => $m[1],  
            );  
        }  
          
        // wstock_HK_Day_5Min_20140930.zip  
        elseif(preg_match(/^wstock_HK_Day_5Min_([0-9]{8})\.zip$/, $basename, $m)){  
            $return = array(  
                    driver => array(  
                            self::HK_SPLIT,  
                            self::HK_DAY,  
                            self::HK_DAY_FORWARD,  
                            self::HK_5MIN,  
                            self::HK_5MIN_FORWARD,  
                    ),  
                    date => $m[1],  
            );  
        }  
          
        else{  
            return false;  
        }  
          
        $return[date] = self::filter_date($return[date]);  
  
        if(!$return[date]){  
            return false;  
        }else{  
            return $return;  
        }  
    }  
      
    /** 
     * 转换为文件系统字符集编码的文件名称 
     * @param string $name 
     */  
    public static function convert2filesystemname($file){  
        return String::autoCharset($file, C(DEFAULT_CHARSET), C(FILE_SYSTEM_ENCODING));  
    }  
      
    /** 
     * 判断本地文件系统中文件是否存在 
     * @param string $file 
     * @return boolean 
     */  
    public static function file_exists($file){  
        $file = self::convert2filesystemname($file);  
        return file_exists($file);  
    }  
      
    /** 
     * 返回每日更新解压后的文件名称 
     * @param string $date 日志 
     * @return string 
     */  
    protected function _get_update_file($date){  
        $update_dir = $this->_get_update_dir($date);  
        $update_fname = self::guess_update_file_name($this->_driver, $date, $update_dir);  
        if(!$update_fname){  
            return $this->_trigger_error("Cann‘t guess update file name!"  
                    , self::ERR_GUESS_FILE  
                    , array(driver=>$this->_driver, date => $date)  
                    , __FILE__  
                    , __LINE__  
            );  
              
            return false;  
        }  
  
        if(is_array($update_fname)){  
            $return = array();  
            foreach($update_fname as $f){  
                $return[] = $update_dir . $f;  
            }  
            return $return;  
        }else{  
            return  $update_dir . $update_fname;  
        }  
          
    }  
      
    /** 
     * 返回更新(解压后)目录 
     * @param string $date 日期 
     * @param string $autocreate 目录不存在是否自动创建 
     * @return boolean|string 
     */  
    protected function _get_update_dir($date, $autocreate=false){  
        $update_folder = date(Ymd, strtotime($date));  
        $update_folder .= /;  
          
        $update_dir = $this->_update_path . $update_folder;  
          
        if($autocreate && !file_exists($this->_update_path) && !mkdir($this->_update_path)){  
            return $this->_trigger_error("Cann‘t create update path!"  
                    , self::ERR_OTHER_MISC  
                    , array(driver=>$this->_driver, date => $date, update_path=>$this->_update_path  
                    )  
                    , __FILE__  
                    , __LINE__  
            );  
        }  
          
        if($autocreate && !file_exists($update_dir) && !mkdir($update_dir, 0777, true)){  
            return $this->_trigger_error("Cann‘t create update dir!"  
                    , self::ERR_FILE_CREATE  
                    , array(driver=>$this->_driver, date => $date, update_dir=>$update_dir  
            )  
                    , __FILE__  
                    , __LINE__  
            );  
        }  
          
        return $update_dir;  
    }  
      
    /** 
     * 返回每日下载文件 
     * @param string $date 日期 
     * @return boolean|string 
     */  
    protected function _get_down_file($date){  
        $down_fname = self::guess_down_file_name($this->_driver, $date);  
        if(!$down_fname){  
            return $this->_trigger_error("Cann‘t guest down file name!"  
                    , self::ERR_GUESS_FILE  
                    , array(driver=>$this->_driver, date => $date)  
                    , __FILE__  
                    , __LINE__  
            );  
        }  
      
        return $this->_get_down_dir($date) . $down_fname;  
    }  
      
    /** 
     * 返回每日下载目录 
     * @param string $date 日期 
     * @return string 
     */  
    protected function _get_down_dir($date){  
        $down_folder = date(Ymd, strtotime($date));  
        $down_folder .= /;  
      
        return $this->_down_path . $down_folder;  
    }  
      
    /** 
     * 返回实时更新数据目录 
     * @param string $date 
     * @param string $autocreate 
     * @return boolean|string 
     */  
    protected function _get_realtime_dir($date, $autocreate=false){  
        $folder = date(Ymd, strtotime($date));  
        $folder .= /;  
      
        $realtime_dir = $this->_realtime_path . $folder;  
      
        if($autocreate && !file_exists($this->_realtime_path) && !mkdir($this->_realtime_path)){  
            return $this->_trigger_error("Cann‘t create realtime path!"  
                    , self::ERR_FILE_CREATE  
                    , array(driver=>$this->_driver, date => $date, realtime_path=>$this->_realtime_path  
                    )  
                    , __FILE__  
                    , __LINE__  
            );  
        }  
      
        if($autocreate && !file_exists($realtime_dir) && !mkdir($realtime_dir, 0777, true)){  
            return $this->_trigger_error("Cann‘t create realtime dir!"  
                    , self::ERR_FILE_CREATE  
                    , array(driver=>$this->_driver, date => $date, realtime_dir=>$realtime_dir  
                    )  
                    , __FILE__  
                    , __LINE__  
            );  
        }  
      
        return $realtime_dir;  
    }  
      
    /** 
     * 返回日志目录 
     * @param string $date 日期 
     * @param string $autocreate 目录不存在是否自动创建 
     * @return boolean|string 
     */  
    protected function _get_log_dir($date, $autocreate=false){  
        $folder = date(Ymd, strtotime($date));  
        $folder .= /;  
      
        $dir = $this->_log_path . $folder;  
      
        if($autocreate && !file_exists($this->_log_path) && !mkdir($this->_log_path)){  
            return $this->_trigger_error("Cann‘t create path!"  
                    , self::ERR_FILE_CREATE  
                    , array(driver=>$this->_driver, date => $date, path=>$this->_log_path  
                    )  
                    , __FILE__  
                    , __LINE__  
            );  
        }  
      
        if($autocreate && !file_exists($dir) && !mkdir($dir, 0777, true)){  
            return $this->_trigger_error("Cann‘t create dir!"  
                    , self::ERR_FILE_CREATE  
                    , array(driver=>$this->_driver, date => $date, dir=>$dir  
                    )  
                    , __FILE__  
                    , __LINE__  
            );  
        }  
      
        return $dir;  
    }  
      
    /** 
     * 发送GET请求 
     *  
     * @param string $url   链接 
     * @param string|array $data    参数 
     * @return string 
     */  
    public function get($url, $data = null) {  
        if(!$this->Http){  
            import(ORG.Net.curl);  
            $this->Http = new Curl();  
        }  
          
        if(!($return = $this->Http->get($url, $data)) && ($error=$this->Http->getError())){  
            return $this->_trigger_error(  
                      $error  
                    , self::ERR_HTTP_REQUEST  
                    , array(url => $url, data => $data, method => get, response => $return)   
                    , __FILE__, __LINE__);  
        }  
          
  
        return $return;  
    }  
      
    protected function _begin_dblog($file){  
        $this->_log_id = $this->_VM()->table(stock_update_log)  
        ->add(array(  
                begintime => date(Y-m-d H:i:s),  
                driver => $this->_driver,  
                datafile => $file,  
                logfile => $this->_log,  
                updatestatus => running,  
        ));  
          
        return $this->_log_id;  
    }  
      
    protected function _end_dblog($status, $message=NULL){  
        if(!$this->_log_id){  
            return false;  
        }  
          
        return $this->_VM()->table(stock_update_log)  
        ->where(array(id=>$this->_log_id))  
        ->save(array(  
                records => $this->_stats[total],  
                succs => $this->_stats[succ],  
                fails => $this->_stats[fail],  
                  
                costsecs => $this->_stats[costsecs],  
                usedmemory => $this->_stats[usedmemory],  
                peakmemory => $this->_stats[peakmemory],  
                  
                endtime => date(Y-m-d H:i:s),  
                updatestatus => $status?succ:fail,  
                updatemsg => (is_object($message) && $message instanceof Exception)?$message->__toString():$message,  
        ));  
    }  
      
    /** 
     * 从文件名分析出数据日期 
     * @param string $file 数据文件名称 
     * @param string $pattern 匹配正则 
     * @param string $default_year 默认年份 
     * @return string 
     */  
    protected function _parse_file_date($file, $pattern, $default_year=NULL){  
        static $_file_dates = array();  
          
        $fidx = md5($file);  
          
        // 分析文件日期  
        //if(!$_file_dates[$fidx]){  
        if(empty($_file_dates[$fidx])){  
            $fileName = basename($file);  
            $date = NULL;  
            if(preg_match($pattern, $fileName, $m)){  
                $date = $m[1];  
                if(strlen($date)==4 && $default_year){  
                    $date = $default_year . $date;  
                }  
                $date = self::filter_date($date);  
            }  
  
            if(!$date){  
                return $this->_trigger_error("Cann‘t parse date from file name"  
                        , self::ERR_OTHER_MISC  
                        , array(file => $file)  
                        , __FILE__, __LINE__  
                );  
            }  
              
            $_file_dates[$fidx] = $date;  
        }  
          
        return $_file_dates[$fidx];  
    }  
  
    /** 
     * 从数据文件名称分析出股票代码 
     * @param string $file 数据文件名称 
     * @param string $pattern 匹配正则 
     * @return string 
     */  
    protected function _parse_file_stock_code($file, $pattern){  
        static $_file_stocks = array();  
          
        $fidx = md5($file);  
          
        // 分析文件日期  
        //if(!$_file_stocks[$fidx]){  
        if(empty($_file_stocks[$fidx])){  
            $fileName = basename($file);  
            $date = NULL;  
            if(preg_match($pattern, $fileName, $m)){  
                $stock = $m[1];  
                $stock = self::filter_stock_code($stock);  
            }  
              
            if(!$stock){  
                return $this->_trigger_error("Cann‘t parse stock code from file name"  
                        , self::ERR_OTHER_MISC  
                        , array(file => $file)  
                        , __FILE__, __LINE__  
                );  
            }  
              
            $_file_stocks[$fidx] = $stock;  
        }  
          
        return $_file_stocks[$fidx];  
    }  
      
    /** 
     * 从数据文件名称分析出数据源 
     * @param string $file 数据文件 
     * @param number $limit 返回目录层次 
     * @return string 
     */  
    protected function _parse_file_source($file, $limit=3){  
        static $_file_sources = array();  
          
        $fidx = md5($file);  
          
        // 分析文件源  
        if(empty($_file_sources[$fidx])){  
            if (preg_match ( ~(((\/|\\\)[^\/\\\]+){1, . $limit . })$~, $file, $m )) {  
                $source = substr($m[1], 1);  
            }else{  
                $source = $file;  
            }  
            $_file_sources[$fidx] = $source;  
        }  
          
        return $_file_sources[$fidx];  
    }  
      
    /** 
     * 更新沪深股票名称 
     * @param string $file 股票名称更新文件 
     * @return mixed 
     */  
    public function updateSHSZStockName($file){  
        $fields = array  
            (  
                    Symbol => array  
                    (  
                            column => A,  
                            title => 代码  
                    ),  
                    CName => array  
                    (  
                            column => B,  
                            title => 中文  
                    ),  
                    EName => array  
                    (  
                            column => C,  
                            title => 英文简写  
                    ),  
            );;  
      
        $options = array(  
                titleRow => 1,  //  标题行数  
                dataRow => 2, // 数据开始行数  
                instantWrite => true, // 实时写  
                fieldCallback => array($this, _cb_field_update_stock_name),  
                rowCallback => array($this, _cb_row_update_stock_name),  
      
                fromEncoding => GBK,  
                toEncoding => UTF-8,  
      
                //‘checkUpdateDate‘ => true, // 只更新比当前日期新的纪录  
        );  
      
        return $this->_importFile($file, $fields, $options);  
    }  
      
    /** 
     * 更新港股股票名称 
     * @param string $file 股票名称更新文件 
     * @return mixed 
     */  
    public function updateHKStockName($file){  
        $fields = array  
        (  
                Symbol => array  
                (  
                        column => A,  
                        title => Code  
                ),  
                EName => array  
                (  
                        column => B,  
                        title => English Name  
                ),  
        );;  
      
        $options = array(  
                titleRow => 1,  //  标题行数  
                dataRow => 2, // 数据开始行数  
                instantWrite => true, // 实时写  
                fieldCallback => array($this, _cb_field_update_stock_name),  
                rowCallback => array($this, _cb_row_update_stock_name),  
      
                fromEncoding => GBK,  
                toEncoding => UTF-8,  
      
                //‘checkUpdateDate‘ => true, // 只更新比当前日期新的纪录  
        );  
      
        return $this->_importFile($file, $fields, $options);  
    }  
      
    public function _cb_field_update_stock_name($file, $line, $column, $field, $value, $options=NULL){  
        $value = self::filter_trim($value);  
        switch($field){  
            // 股票代码  
            case stock:  
                $value = self::filter_stock_code($value);  
                if(!$value){  
                    return true;  
                }  
                break;  
        }  
      
        return $value;  
    }  
      
    public function _cb_row_update_stock_name($file, $line, $fieldValues, $rowValues, $options=NULL){  
        $this->_stats[total]++;  
      
        $table = stock_symbol;  
        $key = Symbol;  
      
        // 添加字段  
        $options[_addFieldValues] = array(  
                Name => $fieldValues[CName]?$fieldValues[CName]:$fieldValues[EName],  
                created_time => date(Y-m-d H:i:s),  
        );  
          
        // 更新字段  
        /* 
        $options[‘_updateFieldValues‘] = array( 
                ‘modified_time‘ => date(‘Y-m-d H:i:s‘), 
        );*/  
          
        $c_sql = self::_cb_row_save($table, $key, $file, $line, $fieldValues, $rowValues, $options);  
      
        if(!$c_sql){  
            //$this->_stats[‘fail‘]++;  
            $this->_stats[fail][] = $line;  
        }else{  
            $this->_stats[succ]++;  
        }  
      
        if(!empty($options[instantWrite])){  
            return $c_sql;  
        }else{  
            $sqls = array();  
      
            if($c_sql){  
                $sqls[] = $c_sql;  
            }  
            return implode(;, $sqls);  
        }  
    }  
      
    /** 
     * 添加监听器 
     * @param mixed $listener 监听器 
     * @param string $type 监听类型 
     */  
    public static function addListener($listener, $type){  
        if(empty(self::$_listners)){  
            self::$_listners = array();  
        }  
          
        if(empty(self::$_listners[$type])){  
            self::$_listners[$type] = array();  
        }  
          
        self::$_listners[$type][] = $listener;  
    }  
      
    protected function _callListener($type, $data){  
        if(empty(self::$_listners[$type])){  
            return false;  
        }  
          
        foreach(self::$_listners[$type] as $listener){  
            $this->_run_callback($listener, $data);  
        }  
    }  
      
    public function archive_data(){  
        $this->_log("=======================================");  
        $this->_log("START Archive DATA");  
          
        $driver = $this->_driver;  
        if(!$driver){  
            $this->_log("Driver cann‘t be empty", LOG::ERR);  
            $this->_log("Stop Archive.");  
            return false;  
        }  
          
        $this->_log("Driver: " . $driver);  
          
        $table = self::getTable($driver);  
        if(!$table){  
            $this->_log("Cann‘t find table", LOG::ERR);  
            $this->_log("Stop Archive.");  
            return false;  
        }  
          
        $table_archive = $table . _archive;  
          
        $this->_log("Table: " . $table);  
        $this->_log("Archive Table: " . $table_archive);  
          
        $archiveDays = self::getArchiveDays($driver);  
        if(!$archiveDays || $archiveDays<=0){  
            $this->_log("Archive day less than 1 day", LOG::ERR);  
            $this->_log("Stop Archive.");  
            return false;  
        }  
          
        $this->_log("Archive Days: " . $archiveDays);  
      
        import(ORG.Util.Debug);  
      
        $debug_start_mark = start_archive_ . $driver;  
        $debug_end_mark = end_archive_ . $driver;  
        Debug::mark($debug_start_mark);  
      
        $archiveDate = date(Y-m-d, strtotime(- . $archiveDays . days));  
          
        $this->_log(Archive data before  . $archiveDate);  
          
  
        $mysqli = $this->_mysqli ();  
      
        switch($driver){  
            case self::SHSZ_DAY:  
            case self::SHSZ_DAY_FORWARD:  
            case self::HK_DAY:  
            case self::HK_DAY_FORWARD:  
                $insert_sql = "INSERT INTO {$table_archive} SELECT * FROM {$table} WHERE date<‘{$archiveDate}‘";  
                $delete_sql = "DELETE FROM {$table} WHERE date<‘{$archiveDate}‘";  
                break;  
                  
            case self::SHSZ_5MIN:  
            case self::SHSZ_5MIN_FORWARD:  
            case self::HK_5MIN:  
            case self::HK_5MIN_FORWARD:  
                $archiveDateTime = $archiveDate .  00:00:00;  
                $insert_sql = "INSERT INTO {$table_archive} SELECT * FROM {$table} WHERE datetime<‘{$archiveDateTime}‘";  
                $delete_sql = "DELETE FROM {$table} WHERE datetime<‘{$archiveDateTime}‘";  
                break;  
                  
            default:  
                $this->_log("Not supported driver");  
                $this->_log("Stop Archive.");  
                return false;  
        }  
          
        $repair_sql = "REPAIR TABLE {$table}";  
        $optimize_sql = "OPTIMIZE TABLE {$table}";  
          
        $this->_log("Insert SQL: " . $insert_sql, LOG::DEBUG);  
        $this->_log("Delete SQL: " . $delete_sql, LOG::DEBUG);  
          
        //return $insert_sql . "\n\n" . $delete_sql;  
          
          
        $this->_log("Try to insert into archive table");  
        if (false ==$mysqli->query ( $insert_sql )) {  
            $this->_log ( sprintf ( Query Error(%s) %s, $mysqli->errno, $mysqli->error ), LOG::ERR );  
            return false;  
        }  
        $inserted_rows = $mysqli->affected_rows;  
        $this->_log("Insert Succ!");  
        $this->_log("Inserted Rows: " . $inserted_rows);  
          
          
          
        $this->_log("Try to delete from table");  
        if (false ==$mysqli->query ( $delete_sql )) {  
            $this->_log ( sprintf ( Query Error(%s) %s, $mysqli->errno, $mysqli->error ), LOG::ERR );  
            return false;  
        }  
        $deleted_rows = $mysqli->affected_rows;  
        $this->_log("Delete Succ!");  
        $this->_log("Deleted Rows: " . $deleted_rows);  
          
          
        $this->_log("Try to repair table");  
        if (false ==$mysqli->query ( $repair_sql )) {  
            $this->_log ( sprintf ( Query Error(%s) %s, $mysqli->errno, $mysqli->error ), LOG::ERR );  
            return false;  
        }  
        $this->_log("Repair Succ!");  
          
          
        $this->_log("Try to optimize table");  
        if (false ==$mysqli->query ( $optimize_sql )) {  
            $this->_log ( sprintf ( Query Error(%s) %s, $mysqli->errno, $mysqli->error ), LOG::ERR );  
            return false;  
        }  
        $this->_log("Optimize Succ!");  
      
        Debug::mark ( $debug_end_mark );  
        $performance = "Cost time " . Debug::useTime ( $debug_start_mark, $debug_end_mark ) . s;  
        $performance .= ", used memory " . Debug::useMemory ( $debug_start_mark, $debug_end_mark ) . kb;  
        $performance .= ", peak memory " . Debug::getMemPeak ( $debug_start_mark, $debug_end_mark ) . kb;  
        $this->_log ( $performance );  
      
        $this->_log ( "END ARCHIVE DATA" );  
      
        return "Inserted Rows: {$inserted_rows}, Deleted Rows: {$deleted_rows}";  
    }  
  
}  


SHSZRealtime.class.php  沪深实时数据更新

[php] view plain copy
<?php defined(IN_HEAVEN) or die(Hacking Attempt!);  
/** 
 * 股票数据导入: 6-沪深实时数据 
 *  
 * PHP version 5 
 *  
 * @category    4SWeb 
 * @package     Admin 
 * @subpackage  Custom 
 * @version     SVN: $Id: SHSZRealtime.class.php 48 2014-11-16 13:25:47Z blin.z $ 
 */  
class SHSZRealtime extends StockImport{  
    protected $_table = shsz_realtime;  
    protected $_table_5min = shsz_realtime_5min;  
    protected $_market = SHSZ;  
      
    public function importFile($file, $file_content=NULL){  
        $fields = array(  
                Time => array(title => Time, format => l, length => 4),  
                Symbol => array(title => Symbol, format => ‘‘, length => 12),  
                Name => array(title => Name, format => ‘‘, length => 16),  
                  
                Price3 => array(title => Price3, format => f, length => 4),  
                Vol2 => array(title => Vol2, format => f, length => 4),  
                OpenInt => array(title => OpenInt, format => f, length => 4),  
                Price2 => array(title => Price2, format => f, length => 4),  
                LastClose => array(title => LastClose, format => f, length => 4),  
                Open => array(title => Open, format => f, length => 4),  
                High => array(title => High, format => f, length => 4),  
                Low => array(title => Low, format => f, length => 4),  
                NewPrice => array(title => NewPrice, format => f, length => 4),  
                Volume => array(title => Volume, format => f, length => 4),  
                Amount => array(title => Amount, format => f, length => 4),  
                BP1 => array(title => BP1, format => f, length => 4),  
                BP2 => array(title => BP2, format => f, length => 4),  
                BP3 => array(title => BP3, format => f, length => 4),  
                BP4 => array(title => BP4, format => f, length => 4),  
                BP5 => array(title => BP5, format => f, length => 4),  
                BV1 => array(title => BV1, format => f, length => 4),  
                BV2 => array(title => BV2, format => f, length => 4),  
                BV3 => array(title => BV3, format => f, length => 4),  
                BV4 => array(title => BV4, format => f, length => 4),  
                BV5 => array(title => BV5, format => f, length => 4),  
                SP1 => array(title => SP1, format => f, length => 4),  
                SP2 => array(title => SP2, format => f, length => 4),  
                SP3 => array(title => SP3, format => f, length => 4),  
                SP4 => array(title => SP4, format => f, length => 4),  
                SP5 => array(title => SP5, format => f, length => 4),  
                SV1 => array(title => SV1, format => f, length => 4),  
                SV2 => array(title => SV2, format => f, length => 4),  
                SV3 => array(title => SV3, format => f, length => 4),  
                SV4 => array(title => SV4, format => f, length => 4),  
                SV5 => array(title => SV5, format => f, length => 4),  
        );  
      
        $options = array(  
                dataRow => 1, // 数据开始行数  
                instantWrite => false, // 实时写  
                //‘fieldCallback‘ => array($this, ‘_cb_field‘),  
                rowCallback => array($this, _cb_row),  
      
                //‘fromEncoding‘ => ‘GBK‘,  
                //‘toEncoding‘ => ‘UTF-8‘,  
                  
                length => 156,  
        );  
      
        return $this->_importFile($file, $fields, $options, $file_content);  
    }  
      
    public function runDownImport($truncate=false, $save=false){  
        import(ORG.Util.Debug);  
          
        $debug_start_mark = start_import_realtime;  
        $debug_end_mark = end_import_realtime;  
          
        Debug::mark($debug_start_mark);  
          
        $this->_log("=======================================");  
        $this->_log("START DOWN & IMPORT RealTime");  
          
        $url = C(WSTOCK_REALTIME_URL..$this->_market);  
          
        if(!$url){  
            $this->_log("RealTime URL is empty.", LOG::ERR);  
            $this->_log("Quit, Do Nothing.");  
            return false;  
        }  
          
        Debug::mark(start_download_realtime_file);  
          
        $this->_download_stamp = time();  
        $this->_download_time = date(Y-m-d H:i:s);  
          
        $this->_log("Try to get data from URL");  
        $this->_log("Download Record Time: " . $this->_download_time);  
          
        $this->_log("Request URL: " . $url, LOG::DEBUG);  
                  
        $content = $this->get($url);  
        if(!$content){  
            $this->_log("Get empty data from URL", LOG::ERR);  
            $this->_log("Quit, Do Nothing.");  
            return false;  
        }else{  
            $this->_log("Succ Down realtime file!");  
        }  
          
        Debug::mark(end_download_realtime_file);  
          
        $down_secs = Debug::useTime(start_download_realtime_file,end_download_realtime_file);  
          
        $this->_log("Cost time " . $down_secs .s);  
          
        // 是否超时?  
        $interval = C(STOCK_REALTIME_UPDATE_INTERVAL);  
        if($interval && $down_secs && ($down_secs>=($interval/2))){  
            $this->_log("Skip Update!");  
            $this->_log("Download cost time more than half interval time $interval/2", LOG::ERR);  
            return false;  
        }  
          
        if(!self::_is_zip($content)){  
            $this->_log("Server returned info package");  
            $this->_log("Info: " . $content);  
            $this->_log("Quit, Do Nothing.");  
            return false;  
        }  
          
        $realtime_dir = $this->_get_realtime_dir(date(Y-m-d), $save);  
          
        list ( $usec, $sec ) = explode ( " ", microtime () );  
        $microtime = trim(( float ) $usec + ( float ) $sec);  
          
        if(!preg_match(/[\?&]m=([A-Z,]+)&?/, $url, $matches)){  
            $this->_log("Invalid realtime URL: " . $url, LOG::ERR);  
            $this->_log("Quit, Do Nothing.");  
            return false;  
        }  
          
        $market = $matches[1];  
        $realtime_file = $realtime_dir . wsRealtime_ . $market . _ . $microtime . .wsz;  
          
        if($save){  
            if(!file_put_contents($realtime_file, $content)){  
                $this->_log("Cann‘t Save realtime file: " . $realtime_file, LOG::ERR);  
                $this->_log("Quit, Do Nothing.");  
                return false;  
            }else{  
                $this->_log("Succ Saved realtime file as " . $realtime_file);  
            }  
        }  
  
        if($truncate){  
            $this->_log("Truncate table before import");  
            $succ = $this->_VM()->execute(TRUNCATE TABLE ` . $this->_table . "`");  
            $this->_log($succ!==false?"Succ":"Fail: " . $this->_VM()->getDbError ());  
        }  
          
        $this->importFile($realtime_file, $content);  
  
        Debug::mark($debug_end_mark);  
          
        $performance = "Cost time " . Debug::useTime($debug_start_mark,$debug_end_mark).s;  
        $performance .= ", used memory " . Debug::useMemory($debug_start_mark,$debug_end_mark).kb;  
        $performance .= ", peak memory " . Debug::getMemPeak($debug_start_mark, $debug_end_mark).kb;  
        $this->_log( $performance );  
          
        $this->_log("END IMPORT RealTime.");  
    }  
      
    public function _cb_field($file, $line, $column, $field, $value, $options=NULL){  
        $value = self::filter_trim($value);  
        switch($field){  
            // 股票代码  
            case Symbol:  
                $value = String::autoCharset($value, gbk, C(DEFAULT_CHARSET));  
                $value = trim($value);  
                $v = self::filter_stock_code($value);  
                if(!$value){  
                    return true;  
                }  
                break;  
                  
            // 名称  
            case Name:  
                $value = String::autoCharset($value, gbk, C(DEFAULT_CHARSET));  
                $value = trim($value);  
                break;  
      
            // 时间转换  
            case Time:  
                //$v = self::filter_date($value);  
                //$v = date(‘Y-m-d H:i:s‘, $v);  
                if(!$value){  
                    return true;  
                }  
                break;  
                  
            case Price3:  
            case Vol2:  
            case OpenInt:  
            case Price2:  
            case LastClose:  
            case Open:  
            case High:  
            case Low:  
            case NewPrice:  
            case Volume:  
            case Amount:  
            case BP1:  
            case BP2:  
            case BP3:  
            case BP4:  
            case BP5:  
            case BV1:  
            case BV2:  
            case BV3:  
            case BV4:  
            case BV5:  
            case SP1:  
            case SP2:  
            case SP3:  
            case SP4:  
            case SP5:  
            case SV1:  
            case SV2:  
            case SV3:  
            case SV4:  
            case SV5:  
                $value = sprintf(%.3f, $value);  
                break;    
        }  
      
        return $value;  
    }  
      
    public function _cb_row($file, $line, $fieldValues, $rowValues, $options=NULL){  
        $this->_stats[total]++;  
      
        $fieldValues[Symbol] = trim(mb_convert_encoding( $fieldValues[Symbol], utf-8, gbk ));  
        $fieldValues[Name] = trim(mb_convert_encoding( $fieldValues[Name], utf-8, gbk ));  
          
        static $float_fields = array(  
                Price3 ,  
                Vol2 ,  
                OpenInt ,  
                Price2 ,  
                LastClose ,  
                Open ,  
                High ,  
                Low ,  
                NewPrice ,  
                Volume ,  
                Amount ,  
                BP1 ,  
                BP2 ,  
                BP3 ,  
                BP4 ,  
                BP5 ,  
                BV1 ,  
                BV2 ,  
                BV3 ,  
                BV4 ,  
                BV5 ,  
                SP1 ,  
                SP2 ,  
                SP3 ,  
                SP4 ,  
                SP5 ,  
                SV1 ,  
                SV2 ,  
                SV3 ,  
                SV4 ,  
                SV5 ,  
        );  
          
        foreach($float_fields as $f){  
            if(isset($fieldValues[$f])){  
                $fieldValues[$f] = sprintf ( %.3f, $fieldValues[$f] );  
            }  
        }  
  
        $fieldValues[recordtime] = $this->_download_time;  
        $sql = SQLKit::replace_stmt($this->_table, $fieldValues);  
          
        $this->_stats[succ]++;  
          
        return $sql;  
    }  
      
    /** 
     * 判断是否为压缩文件 
     * @param string $content 
     * @return boolean 
     */  
    protected function _is_zip($content){  
        $tagstr = substr($content, 0, 4);  
        $tagnum = current(unpack("l", $tagstr));  
        return ($tagnum>16777216 || $tagnum<=0)?false:true;  
    }  
      
    protected function _decode($content){  
        $length = strlen($content);  
        if(!$length){  
            return $this->_trigger_error(  
                    "File content is empty"  
                    , self::ERR_EMPTY_DATA  
                    , null  
                    , __FILE__, __LINE__  
            );  
        }  
          
        $readpos = 0;  
        $rawdata = ‘‘;  
        while($readpos<$length){  
            //$blocksize = $this->_readcontent($content, $this->_readpos, 4);  
            $blocksize = substr($content, $readpos, 4);  
            $readpos += 4;  
              
            $blocksize= current(unpack("l", $blocksize));  
              
            if(!$blocksize || $blocksize<=0){  
                return $this->_trigger_error(  
                        "Block size is zero or negative"  
                        , self::ERR_FILE_READ  
                        , array(readpos=>$readpos)  
                        , __FILE__, __LINE__  
                );  
            }  
              
            $zipsize = $blocksize - 4;  
            if ($zipsize <= 0) {  
                return $this->_trigger_error (   
                        "Zip size is zero or negative"  
                        , self::ERR_FILE_READ  
                        , array (  
                            readpos => $readpos  
                        )  
                        , __FILE__, __LINE__ );  
            }  
              
            //$orisize = $this->_readcontent($content, $this->_readpos, 4);  
            $orisize = substr($content, $readpos, 4);  
            $readpos += 4;  
              
            $orisize= current(unpack("l", $orisize));  
            if ($orisize <= 0) {  
                return $this->_trigger_error (  
                        "Ori size is zero or negative"  
                        , self::ERR_FILE_READ  
                        , array (  
                                readpos => $this->_readpos  
                        )  
                        , __FILE__, __LINE__ );  
            }  
              
            //$zipbody = $this->_readcontent($content, $this->_readpos, $zipsize);  
            $zipbody = substr($content, $readpos, $zipsize);  
            $readpos += $zipsize;  
              
            if (!$zipbody) {  
                return $this->_trigger_error (  
                        "Zip body is empty"  
                        , self::ERR_FILE_READ  
                        , array (  
                                readpos => $this->_readpos  
                        )  
                        , __FILE__, __LINE__ );  
            }  
              
            $zipbody = zlib_decode($zipbody);  
            if (!$zipbody) {  
                return $this->_trigger_error (  
                        "Cann‘t decode zip body"  
                        , self::ERR_FILE_READ  
                        , array (  
                                readpos => $this->_readpos  
                        )  
                        , __FILE__, __LINE__ );  
            }  
              
            $rawdata .= $zipbody;  
        }  
          
        return $rawdata;  
    }  
      
    protected function _readcontent($content, $start, $length){  
        $this->_readpos += $length;  
        return substr($content, $start, $length);  
    }  
  
    protected function _import($file, $fields, $options=array(), $content=NULL){  
        $default_options = array(  
                titleRow => false, //  标题行数,设置才会检测Excel标题列是否符合要求  
                dataRow => 1, // 数据开始行数,可以通过传数组方式设置读取的开始和终止行数,格式如array(开始行数,终止行数)  
                rowCallback => NULL, // 行数据处理回调,传参数:$row, $fieldValues, $rowValues, $options  
                fieldCallback => NULL, // 字段过滤处理回调,传参数:$column, $field, $value, $options  
      
                length => NULL, // 行长度  
      
                fromEncoding => NULL, // 源文件编码  
                toEncoding => NULL, // 数据编码  
      
        );  
      
        $options = array_merge($default_options, $options);  
      
        $aColumnMaps = array ( A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, AA, AB, AC, AD, AE, AF, AG, AH, AI, AJ, AK, AL, AM, AN, AO, AP, AQ, AR, AS, AT, AU, AV, AW, AX, AY, AZ, BA, BB, BC, BD, BE, BF, BG, BH, BI, BJ, BK, BL, BM, BN, BO, BP, BQ, BR, BS, BT, BU, BV, BW, BX, BY, BZ, CA, CB, CC, CD, CE, CF, CG, CH, CI, CJ, CK, CL, CM, CN, CO, CP, CQ, CR, CS, CT, CU, CV, CW, CX, CY, CZ, DA, DB, DC, DD, DE, DF, DG, DH, DI, DJ, DK, DL, DM, DN, DO, DP, DQ, DR, DS, DT, DU, DV, DW, DX, DY, DZ, EA, EB, EC, ED, EE, EF, EG, EH, EI, EJ, EK, EL, EM, EN, EO, EP, EQ, ER, ES, ET, EU, EV, EW, EX, EY, EZ, FA, FB, FC, FD, FE, FF, FG, FH, FI, FJ, FK, FL, FM, FN, FO, FP, FQ, FR, FS, FT, FU, FV, FW, FX, FY, FZ, GA, GB, GC, GD, GE, GF, GG, GH, GI, GJ, GK, GL, GM, GN, GO, GP, GQ, GR, GS, GT, GU, GV, GW, GX, GY, GZ, HA, HB, HC, HD, HE, HF, HG, HH, HI, HJ, HK, HL, HM, HN, HO, HP, HQ, HR, HS, HT, HU, HV, HW, HX, HY, HZ, IA, IB, IC, ID, IE, IF, IG, IH, II, IJ, IK, IL, IM, IN, IO, IP, IQ, IR, IS, IT, IU, IV, IW, IX, IY, IZ, JA, JB, JC, JD, JE, JF, JG, JH, JI, JJ, JK, JL, JM, JN, JO, JP, JQ, JR, JS, JT, JU, JV, JW, JX, JY, JZ, KA, KB, KC, KD, KE, KF, KG, KH, KI, KJ, KK, KL, KM, KN, KO, KP, KQ, KR, KS, KT, KU, KV, KW, KX, KY, KZ, LA, LB, LC, LD, LE, LF, LG, LH, LI, LJ, LK, LL, LM, LN, LO, LP, LQ, LR, LS, LT, LU, LV, LW, LX, LY, LZ, MA, MB, MC, MD, ME, MF, MG, MH, MI, MJ, MK, ML, MM, MN, MO, MP, MQ, MR, MS, MT, MU, MV, MW, MX, MY, MZ, NA, NB, NC, ND, NE, NF, NG, NH, NI, NJ, NK, NL, NM, NN, NO, NP, NQ, NR, NS, NT, NU, NV, NW, NX, NY, NZ, OA, OB, OC, OD, OE, OF, OG, OH, OI, OJ, OK, OL, OM, ON, OO, OP, OQ, OR, OS, OT, OU, OV, OW, OX, OY, OZ, PA, PB, PC, PD, PE, PF, PG, PH, PI, PJ, PK, PL, PM, PN, PO, PP, PQ, PR, PS, PT, PU, PV, PW, PX, PY, PZ, QA, QB, QC, QD, QE, QF, QG, QH, QI, QJ, QK, QL, QM, QN, QO, QP, QQ, QR, QS, QT, QU, QV, QW, QX, QY, QZ, RA, RB, RC, RD, RE, RF, RG, RH, RI, RJ, RK, RL, RM, RN, RO, RP, RQ, RR, RS, RT, RU, RV, RW, RX, RY, RZ, SA, SB, SC, SD, SE, SF, SG, SH, SI, SJ, SK, SL, SM, SN, SO, SP, SQ, SR, SS, ST, SU, SV, SW, SX, SY, SZ, TA, TB, TC, TD, TE, TF, TG, TH, TI, TJ, TK, TL, TM, TN, TO, TP, TQ, TR, TS, TT, TU, TV, TW, TX, TY, TZ, UA, UB, UC, UD, UE, UF, UG, UH, UI, UJ, UK, UL, UM, UN, UO, UP, UQ, UR, US, UT, UU, UV, UW, UX, UY, UZ, VA, VB, VC, VD, VE, VF, VG, VH, VI, VJ, VK, VL, VM, VN, VO, VP, VQ, VR, VS, VT, VU, VV, VW, VX, VY, VZ, WA, WB, WC, WD, WE, WF, WG, WH, WI, WJ, WK, WL, WM, WN, WO, WP, WQ, WR, WS, WT, WU, WV, WW, WX, WY, WZ, XA, XB, XC, XD, XE, XF, XG, XH, XI, XJ, XK, XL, XM, XN, XO, XP, XQ, XR, XS, XT, XU, XV, XW, XX, XY, XZ, YA, YB, YC, YD, YE, YF, YG, YH, YI, YJ, YK, YL, YM, YN, YO, YP, YQ, YR, YS, YT, YU, YV, YW, YX, YY, YZ, ZA, ZB, ZC, ZD, ZE, ZF, ZG, ZH, ZI, ZJ, ZK, ZL, ZM, ZN, ZO, ZP, ZQ, ZR, ZS, ZT, ZU, ZV, ZW, ZX, ZY, ZZ );  
        $aColumnFlipMaps = array ( A => 0, B => 1, C => 2, D => 3, E => 4, F => 5, G => 6, H => 7, I => 8, J => 9, K => 10, L => 11, M => 12, N => 13, O => 14, P => 15, Q => 16, R => 17, S => 18, T => 19, U => 20, V => 21, W => 22, X => 23, Y => 24, Z => 25, AA => 26, AB => 27, AC => 28, AD => 29, AE => 30, AF => 31, AG => 32, AH => 33, AI => 34, AJ => 35, AK => 36, AL => 37, AM => 38, AN => 39, AO => 40, AP => 41, AQ => 42, AR => 43, AS => 44, AT => 45, AU => 46, AV => 47, AW => 48, AX => 49, AY => 50, AZ => 51, BA => 52, BB => 53, BC => 54, BD => 55, BE => 56, BF => 57, BG => 58, BH => 59, BI => 60, BJ => 61, BK => 62, BL => 63, BM => 64, BN => 65, BO => 66, BP => 67, BQ => 68, BR => 69, BS => 70, BT => 71, BU => 72, BV => 73, BW => 74, BX => 75, BY => 76, BZ => 77, CA => 78, CB => 79, CC => 80, CD => 81, CE => 82, CF => 83, CG => 84, CH => 85, CI => 86, CJ => 87, CK => 88, CL => 89, CM => 90, CN => 91, CO => 92, CP => 93, CQ => 94, CR => 95, CS => 96, CT => 97, CU => 98, CV => 99, CW => 100, CX => 101, CY => 102, CZ => 103, DA => 104, DB => 105, DC => 106, DD => 107, DE => 108, DF => 109, DG => 110, DH => 111, DI => 112, DJ => 113, DK => 114, DL => 115, DM => 116, DN => 117, DO => 118, DP => 119, DQ => 120, DR => 121, DS => 122, DT => 123, DU => 124, DV => 125, DW => 126, DX => 127, DY => 128, DZ => 129, EA => 130, EB => 131, EC => 132, ED => 133, EE => 134, EF => 135, EG => 136, EH => 137, EI => 138, EJ => 139, EK => 140, EL => 141, EM => 142, EN => 143, EO => 144, EP => 145, EQ => 146, ER => 147, ES => 148, ET => 149, EU => 150, EV => 151, EW => 152, EX => 153, EY => 154, EZ => 155, FA => 156, FB => 157, FC => 158, FD => 159, FE => 160, FF => 161, FG => 162, FH => 163, FI => 164, FJ => 165, FK => 166, FL => 167, FM => 168, FN => 169, FO => 170, FP => 171, FQ => 172, FR => 173, FS => 174, FT => 175, FU => 176, FV => 177, FW => 178, FX => 179, FY => 180, FZ => 181, GA => 182, GB => 183, GC => 184, GD => 185, GE => 186, GF => 187, GG => 188, GH => 189, GI => 190, GJ => 191, GK => 192, GL => 193, GM => 194, GN => 195, GO => 196, GP => 197, GQ => 198, GR => 199, GS => 200, GT => 201, GU => 202, GV => 203, GW => 204, GX => 205, GY => 206, GZ => 207, HA => 208, HB => 209, HC => 210, HD => 211, HE => 212, HF => 213, HG => 214, HH => 215, HI => 216, HJ => 217, HK => 218, HL => 219, HM => 220, HN => 221, HO => 222, HP => 223, HQ => 224, HR => 225, HS => 226, HT => 227, HU => 228, HV => 229, HW => 230, HX => 231, HY => 232, HZ => 233, IA => 234, IB => 235, IC => 236, ID => 237, IE => 238, IF => 239, IG => 240, IH => 241, II => 242, IJ => 243, IK => 244, IL => 245, IM => 246, IN => 247, IO => 248, IP => 249, IQ => 250, IR => 251, IS => 252, IT => 253, IU => 254, IV => 255, IW => 256, IX => 257, IY => 258, IZ => 259, JA => 260, JB => 261, JC => 262, JD => 263, JE => 264, JF => 265, JG => 266, JH => 267, JI => 268, JJ => 269, JK => 270, JL => 271, JM => 272, JN => 273, JO => 274, JP => 275, JQ => 276, JR => 277, JS => 278, JT => 279, JU => 280, JV => 281, JW => 282, JX => 283, JY => 284, JZ => 285, KA => 286, KB => 287, KC => 288, KD => 289, KE => 290, KF => 291, KG => 292, KH => 293, KI => 294, KJ => 295, KK => 296, KL => 297, KM => 298, KN => 299, KO => 300, KP => 301, KQ => 302, KR => 303, KS => 304, KT => 305, KU => 306, KV => 307, KW => 308, KX => 309, KY => 310, KZ => 311, LA => 312, LB => 313, LC => 314, LD => 315, LE => 316, LF => 317, LG => 318, LH => 319, LI => 320, LJ => 321, LK => 322, LL => 323, LM => 324, LN => 325, LO => 326, LP => 327, LQ => 328, LR => 329, LS => 330, LT => 331, LU => 332, LV => 333, LW => 334, LX => 335, LY => 336, LZ => 337, MA => 338, MB => 339, MC => 340, MD => 341, ME => 342, MF => 343, MG => 344, MH => 345, MI => 346, MJ => 347, MK => 348, ML => 349, MM => 350, MN => 351, MO => 352, MP => 353, MQ => 354, MR => 355, MS => 356, MT => 357, MU => 358, MV => 359, MW => 360, MX => 361, MY => 362, MZ => 363, NA => 364, NB => 365, NC => 366, ND => 367, NE => 368, NF => 369, NG => 370, NH => 371, NI => 372, NJ => 373, NK => 374, NL => 375, NM => 376, NN => 377, NO => 378, NP => 379, NQ => 380, NR => 381, NS => 382, NT => 383, NU => 384, NV => 385, NW => 386, NX => 387, NY => 388, NZ => 389, OA => 390, OB => 391, OC => 392, OD => 393, OE => 394, OF => 395, OG => 396, OH => 397, OI => 398, OJ => 399, OK => 400, OL => 401, OM => 402, ON => 403, OO => 404, OP => 405, OQ => 406, OR => 407, OS => 408, OT => 409, OU => 410, OV => 411, OW => 412, OX => 413, OY => 414, OZ => 415, PA => 416, PB => 417, PC => 418, PD => 419, PE => 420, PF => 421, PG => 422, PH => 423, PI => 424, PJ => 425, PK => 426, PL => 427, PM => 428, PN => 429, PO => 430, PP => 431, PQ => 432, PR => 433, PS => 434, PT => 435, PU => 436, PV => 437, PW => 438, PX => 439, PY => 440, PZ => 441, QA => 442, QB => 443, QC => 444, QD => 445, QE => 446, QF => 447, QG => 448, QH => 449, QI => 450, QJ => 451, QK => 452, QL => 453, QM => 454, QN => 455, QO => 456, QP => 457, QQ => 458, QR => 459, QS => 460, QT => 461, QU => 462, QV => 463, QW => 464, QX => 465, QY => 466, QZ => 467, RA => 468, RB => 469, RC => 470, RD => 471, RE => 472, RF => 473, RG => 474, RH => 475, RI => 476, RJ => 477, RK => 478, RL => 479, RM => 480, RN => 481, RO => 482, RP => 483, RQ => 484, RR => 485, RS => 486, RT => 487, RU => 488, RV => 489, RW => 490, RX => 491, RY => 492, RZ => 493, SA => 494, SB => 495, SC => 496, SD => 497, SE => 498, SF => 499, SG => 500, SH => 501, SI => 502, SJ => 503, SK => 504, SL => 505, SM => 506, SN => 507, SO => 508, SP => 509, SQ => 510, SR => 511, SS => 512, ST => 513, SU => 514, SV => 515, SW => 516, SX => 517, SY => 518, SZ => 519, TA => 520, TB => 521, TC => 522, TD => 523, TE => 524, TF => 525, TG => 526, TH => 527, TI => 528, TJ => 529, TK => 530, TL => 531, TM => 532, TN => 533, TO => 534, TP => 535, TQ => 536, TR => 537, TS => 538, TT => 539, TU => 540, TV => 541, TW => 542, TX => 543, TY => 544, TZ => 545, UA => 546, UB => 547, UC => 548, UD => 549, UE => 550, UF => 551, UG => 552, UH => 553, UI => 554, UJ => 555, UK => 556, UL => 557, UM => 558, UN => 559, UO => 560, UP => 561, UQ => 562, UR => 563, US => 564, UT => 565, UU => 566, UV => 567, UW => 568, UX => 569, UY => 570, UZ => 571, VA => 572, VB => 573, VC => 574, VD => 575, VE => 576, VF => 577, VG => 578, VH => 579, VI => 580, VJ => 581, VK => 582, VL => 583, VM => 584, VN => 585, VO => 586, VP => 587, VQ => 588, VR => 589, VS => 590, VT => 591, VU => 592, VV => 593, VW => 594, VX => 595, VY => 596, VZ => 597, WA => 598, WB => 599, WC => 600, WD => 601, WE => 602, WF => 603, WG => 604, WH => 605, WI => 606, WJ => 607, WK => 608, WL => 609, WM => 610, WN => 611, WO => 612, WP => 613, WQ => 614, WR => 615, WS => 616, WT => 617, WU => 618, WV => 619, WW => 620, WX => 621, WY => 622, WZ => 623, XA => 624, XB => 625, XC => 626, XD => 627, XE => 628, XF => 629, XG => 630, XH => 631, XI => 632, XJ => 633, XK => 634, XL => 635, XM => 636, XN => 637, XO => 638, XP => 639, XQ => 640, XR => 641, XS => 642, XT => 643, XU => 644, XV => 645, XW => 646, XX => 647, XY => 648, XZ => 649, YA => 650, YB => 651, YC => 652, YD => 653, YE => 654, YF => 655, YG => 656, YH => 657, YI => 658, YJ => 659, YK => 660, YL => 661, YM => 662, YN => 663, YO => 664, YP => 665, YQ => 666, YR => 667, YS => 668, YT => 669, YU => 670, YV => 671, YW => 672, YX => 673, YY => 674, YZ => 675, ZA => 676, ZB => 677, ZC => 678, ZD => 679, ZE => 680, ZF => 681, ZG => 682, ZH => 683, ZI => 684, ZJ => 685, ZK => 686, ZL => 687, ZM => 688, ZN => 689, ZO => 690, ZP => 691, ZQ => 692, ZR => 693, ZS => 694, ZT => 695, ZU => 696, ZV => 697, ZW => 698, ZX => 699, ZY => 700, ZZ => 701 );  
      
        $aReturn = array();  
        $aReturn5Min = array();  
      
        if(!$options[length]){  
            $options[length] = 0;  
            foreach($fields as $f){  
                $options[length] += $f[length];  
            }  
        }  
          
        //$this->_log("Block length: " . $options[‘length‘]);  
          
        if(!$content){  
            $content = file_get_contents($file);  
        }  
          
        if($content===false){  
            return $this->_trigger_error(  
                    "Cann‘t open file: " . $file  
                    , self::ERR_FILE_READ  
                    , $file  
                    , __FILE__, __LINE__  
            );  
        }  
          
        Debug::mark(start_decode_realtime_file);  
          
        $this->_log("Try to decode data");  
          
        $rawdata = $this->_decode($content);  
        //$rawdata = $content;  
          
        if(!$rawdata){  
            return $this->_trigger_error("Cann‘t decode data"  
                    , self::ERR_FILE_READ  
                    , $file  
                    , __FILE__, __LINE__  
            );  
        }  
          
        $this->_log("Succ decoded!");  
          
        Debug::mark(end_decode_realtime_file);  
          
        $this->_log("Cost time " . Debug::useTime(start_decode_realtime_file,end_decode_realtime_file).s);  
          
        $length = strlen($rawdata);  
        $this->_readpos = 0;  
          
        static $float_fields = array(  
                Price3 ,  
                Vol2 ,  
                OpenInt ,  
                Price2 ,  
                LastClose ,  
                Open ,  
                High ,  
                Low ,  
                NewPrice ,  
                Volume ,  
                Amount ,  
                BP1 ,  
                BP2 ,  
                BP3 ,  
                BP4 ,  
                BP5 ,  
                BV1 ,  
                BV2 ,  
                BV3 ,  
                BV4 ,  
                BV5 ,  
                SP1 ,  
                SP2 ,  
                SP3 ,  
                SP4 ,  
                SP5 ,  
                SV1 ,  
                SV2 ,  
                SV3 ,  
                SV4 ,  
                SV5 ,  
        );  
          
        Debug::mark(start_process_realtime_data);  
          
        $this->_log("Try to process data");  
      
        $line = 0; // 当前行数  
        $readpos = 0; // 当前文件读取位置  
        for ($i=0;$i<$length;$i+=$options[length]) {  
            $line++; // 当前行数+1  
              
            $fieldValues = array(); // 行字段值  
      
            // 行原始数据  
            $rowdata = substr($rawdata, $readpos, $options[length]);  
            $readpos += $options[length];  
              
            // 行数据处理  
            $rowpos = 0; // 当前行读取位置  
  
            $fieldValues[Time] = current(unpack(l, substr($rowdata, $rowpos, 4)));  
            $rowpos += 4;  
              
            $fieldValues[Symbol] = trim(substr($rowdata, $rowpos, 12));  
            $rowpos += 12;  
  
            $fieldValues[Name] = substr($rowdata, $rowpos, 16);  
            $rowpos += 16;  
      
            //$fieldValues[‘Symbol‘] = trim(mb_convert_encoding( $fieldValues[‘Symbol‘], ‘utf-8‘, ‘gbk‘ ));  
            $fieldValues[Name] = trim(mb_convert_encoding( $fieldValues[Name], utf-8, gbk ));  
              
            foreach($float_fields as $f){  
                $fieldValues[$f] = current(unpack(f, substr($rowdata, $rowpos, 4)));  
                $rowpos += 4;  
                  
                $fieldValues[$f] = sprintf ( %.3f, $fieldValues[$f] );  
            }  
                  
            $fieldValues[recordtime] = $this->_download_time;  
            $aReturn[$line] = SQLKit::replace_stmt($this->_table, $fieldValues);  
            $aReturn5Min[$line] = SQLKit::replace_stmt($this->_table_5min, $fieldValues);  
                  
            $this->_stats[total]++;  
            $this->_stats[succ]++;  
        }  
          
        $this->_log("End process realtime data");  
          
        Debug::mark(end_process_realtime_data);  
  
        $this->_log("Cost time " . Debug::useTime(start_process_realtime_data,end_process_realtime_data).s);  
  
        Debug::mark(start_save_realtime_data);  
        $this->_log("Try to save realtime data");  
          
          
        // 写入内存  
        /* 
        $oCache = Cache::getInstance(); 
        $cache_id = ‘SHSZ_REALTIME_DATA‘; 
        $cache_expire = 3600; 
        $cache_data = array( 
                ‘serialized‘ => 0, 
                ‘created‘ => time(), 
                ‘expire‘ => $cache_expire, 
                ‘data‘ => $aReturn, 
        );   
        $oCache->set($cache_id, $cache_data, $cache_expire);*/  
          
        // 写入数据库  
        $mysqli = $this->_mysqli();  
          
        // 检测是否已有更新  
        $interval = C(STOCK_REALTIME_UPDATE_INTERVAL);  
        if($interval && $interval>0 && (time()-$this->_download_stamp)>=$interval && $fieldValues[Time]){  
            /* Select queries return a resultset */  
            $result = $mysqli->query ( "Select Time FROM " . $this->_table . " LIMIT 1" );  
            if ($result) {  
                $row = $result->fetch_assoc ();  
                  
                /* free result set */  
                $result->close ();  
                  
                if ($row && $row [Time] && $row [Time] > $fieldValues [Time]) {  
                    $this->_log("Skip Update!");  
                    $this->_setError("Exist record is newer (" . date ( Y-m-d H:i:s, $row [Time] ) . ") than current download data (" . date ( Y-m-d H:i:s, $fieldValues [Time] ) . ")");  
                    return false;  
                }  
            }  
        }  
  
        //$chunk_sqls = array_chunk($aReturn, 1000);  
        $chunk_sqls = array($aReturn);  
        foreach ( $chunk_sqls as $sqls ) {  
            $query = implode(;, $sqls);  
              
            /* execute multi query */  
            if (false == $mysqli->multi_query ( $query )) {  
                $error = Query Error;  
                $error .=  ( . $mysqli->errno . ) . $mysqli->error;  
                /* 
                do { 
                    $error .= ‘, (‘ . $mysqli->connect_errno . ‘) ‘. $mysqli->connect_error; 
                } while ( $mysqli->next_result () );*/  
                  
                return $this->_trigger_error ( $error, self::ERR_DB_QUERY, NULL, __FILE__, __LINE__ );  
            }  
              
            // 释放结果集  
            do {  
                /* store first result set */  
                if ($result = $mysqli->store_result ()) {  
                    $result->close ();  
                }  
            } while ( $mysqli->next_result () );  
        }  
          
        $chunk_sqls = array($aReturn5Min);  
        foreach ( $chunk_sqls as $sqls ) {  
            $query = implode(;, $sqls);  
                  
            /* execute multi query */  
            if (false == $mysqli->multi_query ( $query )) {  
                $error = Query Error;  
                $error .=  ( . $mysqli->errno . ) . $mysqli->error;  
                return $this->_trigger_error ( $error, self::ERR_DB_QUERY, NULL, __FILE__, __LINE__ );  
            }  
              
            // 释放结果集  
            do {  
                /* store first result set */  
                if ($result = $mysqli->store_result ()) {  
                    $result->close ();  
                }  
            } while ( $mysqli->next_result () );  
        }  
          
        //$mysqli->close();  
          
        $this->_log("End save realtime data");  
          
        Debug::mark(end_save_realtime_data);  
          
        $this->_log("Cost time " . Debug::useTime(start_save_realtime_data,end_save_realtime_data).s);  
          
        return $aReturn;  
    }  
      
    protected function _unpack_row($rowdata, $fields){  
        $rowpos = 0;  
        $rowvalues = array();  
        foreach($fields as $field=>$f){  
            if(empty($f)){  
                continue;  
            }  
      
            $value = substr($rowdata, $rowpos, $f[length]);  
      
            if($f[format]){  
                $value = current(unpack($f[format], $value));  
            }  
      
            $rowpos += $f[length];  
      
            $rowvalues[] = $value;  
        }  
      
        return $rowvalues;  
    }  
      
    protected function _run_field_callback($callback, $file, $line, $column, $field, $value, $options){  
        // 直接回调,提高性能  
        $func = $callback[1];  
        return $this->$func($file, $line, $column, $field, $value, $options);  
  
    }  
      
    protected function _run_row_callback($callback, $file, $line, $fieldValues, $rowValues, $options){  
        // 直接回调,提高性能  
        $func = $callback[1];  
        return $this->$func($file, $line, $fieldValues, $rowValues, $options);  
    }  
      
    public static function autoCharset($string, $from=gbk, $to=utf-8){  
        $from = strtoupper($from) == UTF8 ? utf-8 : $from;  
        $to = strtoupper($to) == UTF8 ? utf-8 : $to;  
        if (strtoupper($from) === strtoupper($to) || empty($string) || (is_scalar($string) && !is_string($string))) {  
            //如果编码相同或者非字符串标量则不转换  
            return $string;  
        }  
        if (is_string($string)) {  
            if (function_exists(mb_convert_encoding)) {  
                return mb_convert_encoding($string, $to, $from);  
            } elseif (function_exists(iconv)) {  
                return iconv($from, $to, $string);  
            } else {  
                return $string;  
            }  
        } elseif (is_array($string)) {  
            foreach ($string as $key => $val) {  
                $_key = self::autoCharset($key, $from, $to);  
                $string[$_key] = self::autoCharset($val, $from, $to);  
                if ($key != $_key)  
                    unset($string[$key]);  
            }  
            return $string;  
        }  
        else {  
            return $string;  
        }  
    }  
      
    /* 
      
     sub subRPT156_CSV { 
    local(*mydata); 
    my($i,$i2,$str,$j,$buffer,@f,$fstr,$s2,$k); 
  
    *mydata = $_[0];$i2=length($mydata);print($i2."\r\n"); 
    $buf1=‘ ‘x1024000;$s2="时间,代码,名称,price3,vol2,Open_Int,price2,LastClose,Open,High,Low,NewPrice,Volume,Amount,BP1,BP2,BP3,BP4,BP5,BV1,BV2,BV3,BV4,BV5,SP1,SP2,SP3,SP4,SP5,SV1,SV2,SV3,SV4,SV5\r\n"; 
    $k=0;&subBufferReplace(*buf1,$s2,$k);$k+=length($s2); 
    for ($i=0;$i<$i2;$i+=156) { 
            $str=substr($mydata,$i,156); 
            $m_time=unpack("l",substr($str,0,4));($sec,$min,$hour,$mday,$mon,$year,$wan) = gmtime($m_time+28800);$year=$year+1900; $mon=$mon+1; 
            $m_szLabel=substr($str,4,12);$m_szLabel=~s/\x00//g;    $m_szName=substr($str,16,16);$m_szName=~s/\x00//g; 
            $fstr="%04d-%02d-%02d %02d:%02d:%02d,%s,%s"; 
            for ($j=0;$j<31;$j++) {    $f[$j]=unpack("f",substr($str,32+$j*4,4)); $fstr.=",%.3f";};$fstr.="\r\n"; 
            $s2=sprintf($fstr,$year,$mon,$mday,$hour,$min,$sec,$m_szLabel,$m_szName,$f[0],$f[1],$f[2],$f[3],$f[4],$f[5],$f[6],$f[7],$f[8],$f[9],$f[10],$f[11],$f[12],$f[13],$f[14],$f[15],$f[16],$f[17],$f[18],$f[19],$f[20],$f[21],$f[22],$f[23],$f[24],$f[25],$f[26],$f[27],$f[28],$f[29],$f[30]); 
            &subBufferReplace(*buf1,$s2,$k);$k+=length($s2); 
    } 
    $mydata=substr($buf1,0,$k); 
    return 1; 
} 
     */  
}  


顶
00
 
 
上一篇FreeBSD10.0上安装Coreseek-4.1补丁
下一篇邮件群发及自动统计退信、动态调整发送策略
  相关文章推荐
? [转] 获取实时股票数据与股票数据接口API
? Presto服务治理与架构优化在京东的实践应用--王哲涵
? 一个用Python编写的股票数据(沪深)爬虫和选股策略测试框架
? 【免费直播】Python最佳学习路线--韦玮
? 股票数据导出分析(一)---数据导入MySQL以及网页表格简单show出来
? JS-SDK开发与微信支付
? 网站实时股票数据接口
? Spring Cloud微服务真实场景实战解析
? 股票数据读取接口Delphi源码,RSR证券实时行情显示
? 10小时深入掌握 Kubernetes
? 股票数据实时获取
? JDK9新特性
? Matlab通过Yahoo与Sina获取历史与实时股票数据
? 实时股票数据接口大全
? 实时股票数据接口大全
? Excel使用VBA读取实时WebService股票数据

查看评论

  暂无评论

您还没有登录,请[登录]或[注册]
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
个人资料
 访问我的空间 
PHP猿
 
 1
访问:3757次
积分:99
等级: 
排名:千里之外
原创:6篇转载:0篇译文:0篇评论:13条
文章搜索

搜索
文章分类
PHP(5)
文章存档
2017年01月(5)
2014年05月(1)
阅读排行
微信公众号接口类(PHP版本)(959)
移动点对点CMPP协议接口类(PHP版本)(862)
历年沪深A股、香港H股票数据导入和实时数据更新展示(782)
在线批量部署网站代码和数据库版本更新升级(435)
FreeBSD10.0上安装Coreseek-4.1补丁(369)
邮件群发及自动统计退信、动态调整发送策略

 

以上是关于港股股票接口访问的问题的主要内容,如果未能解决你的问题,请参考以下文章

R语言获取国内的股票数据

股票基础常识

港股卖空机制

历年沪深A股香港H股票数据导入和实时数据更新展示 ---转载

港股上市!小米开源项目盘点

怎样获取东方财富网的股票数据 如开盘价