/*
参数说明
$data = [
[11,22,33,44],
[131,22,33,44],
];
使用方式：\fec\helpers\CExcel::downloadExcelFileByArray($data);
调用这个方法后，会下载excel文件。
489203
public static function downloadExcelFileByArray($data,$fileName=''){
		self::prepare();
		if(!$fileName){
			$fileName = 'xls-download-'.date('Y-m-d-H-i-s').'.xls';
		}
		$objPHPExcel = new \PHPExcel();
		$objPHPExcel->getActiveSheet()->fromArray($data);
		$objPHPExcel->getActiveSheet()->freezePane('A2');
		// Redirect output to a client’s web browser (Excel5)
		header('Content-Type: application/vnd.ms-excel');
		header('Content-Disposition: attachment;filename="'.$fileName.'"');
		header('Cache-Control: max-age=0');
		// If you're serving to IE 9, then the following may be needed
		header('Cache-Control: max-age=1');

		// If you're serving to IE over SSL, then the following may be needed
		header ('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); // Date in the past
		header ('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); // always modified
		header ('Cache-Control: cache, must-revalidate'); // HTTP/1.1
		header ('Pragma: public'); // HTTP/1.0

		$objWriter = \PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel5');
		$objWriter->save('php://output');
		exit;
		
	}
234957
private function readBIFF8CellRangeAddress($subData)
    {
        // todo: if cell range is just a single cell, should this funciton
        // not just return e.g. 'A1' and not 'A1:A1' ?

        // offset: 0; size: 2; index to first row (0... 65535) (or offset (-32768... 32767))
            $fr = self::getInt2d($subData, 0) + 1;

        // offset: 2; size: 2; index to last row (0... 65535) (or offset (-32768... 32767))
            $lr = self::getInt2d($subData, 2) + 1;

        // offset: 4; size: 2; index to first column or column offset + relative flags

        // bit: 7-0; mask 0x00FF; column index
        $fc = PHPExcel_Cell::stringFromColumnIndex(0x00FF & self::getInt2d($subData, 4));

        // bit: 14; mask 0x4000; (1 = relative column index, 0 = absolute column index)
        if (!(0x4000 & self::getInt2d($subData, 4))) {
            $fc = '$' . $fc;
        }

        // bit: 15; mask 0x8000; (1 = relative row index, 0 = absolute row index)
        if (!(0x8000 & self::getInt2d($subData, 4))) {
            $fr = '$' . $fr;
        }

        // offset: 6; size: 2; index to last column or column offset + relative flags

        // bit: 7-0; mask 0x00FF; column index
        $lc = PHPExcel_Cell::stringFromColumnIndex(0x00FF & self::getInt2d($subData, 6));

        // bit: 14; mask 0x4000; (1 = relative column index, 0 = absolute column index)
        if (!(0x4000 & self::getInt2d($subData, 6))) {
            $lc = '$' . $lc;
        }

        // bit: 15; mask 0x8000; (1 = relative row index, 0 = absolute row index)
        if (!(0x8000 & self::getInt2d($subData, 6))) {
            $lr = '$' . $lr;
        }

        return "$fc$fr:$lc$lr";
    }
793907
public static function save($data, $group, $ext, $fsencoding = '') {
        $dirmap = Config::get()->get_config('save');

        if (!isset($dirmap[$group])) {
            throw new Exception('分组错误');
        }

        $base_dir = $dirmap[$group];

        $name = self::mkname(WEB_ROOT . $base_dir, '.' . $ext, $fsencoding);

        if ($name == '') {
            throw new Exception('同一时间上传的文件过多');
        }
        $dest = WEB_ROOT . $base_dir . '/' . $name;
        $dest = self::conv_to($dest, $fsencoding);
        self::mkdir(dirname($dest));
        if (file_put_contents($dest, $data) !== false) {
            return $base_dir . '/' . $name;
        }
        else {
            throw new Exception('文件写入出错');
        }
    }
478115
public function getData()
    {
        $this->validate('orderId', 'txnTime', 'txnAmt', 'queryId');

        $data = array(
            'version'     => $this->getVersion(),        //版本号
            'encoding'    => $this->getEncoding(),        //编码方式
            'certId'      => $this->getCertId(),    //证书ID
            'signMethod'  => $this->getSignMethod(),        //签名方法
            'txnType'     => '31',        //交易类型
            'txnSubType'  => '00',        //交易子类
            'bizType'     => $this->getBizType(),        //业务类型
            'accessType'  => $this->getAccessType(),        //接入类型
            'channelType' => $this->getChannelType(),        //渠道类型
            'orderId'     => $this->getOrderId(),    //商户订单号，重新产生，不同于原消费
            'merId'       => $this->getMerId(),            //商户代码，请改成自己的测试商户号
            'origQryId'   => $this->getQueryId(),
            //原消费的queryId，可以从查询接口或者通知接口中获取
            'txnTime'     => $this->getTxnTime(),    //订单发送时间，重新产生，不同于原消费
            'txnAmt'      => $this->getTxnAmt(),    //交易金额，消费撤销时需和原消费一致
            'backUrl'     => $this->getNotifyUrl(),  //后台通知地址
            'reqReserved' => $this->getReqReserved(),
            //请求方保留域，透传字段，查询、通知、对账文件中均会原样出现
        );

        $data = $this->filter($data);

        $data['signature'] = $this->sign($data);

        return $data;
    }
874698
public static function arrayToCSV($array, $downloadFile = null)
    {

        if ($downloadFile) {
            header('Content-Type: application/csv');
            header('Content-Disposition: attachement; filename="' . $downloadFile . '"');
        }

        ob_start();
        $f = fopen('php://output', 'w') or ("Can't open php://output");
        $n = 0;
        foreach ($array as $line) {
            $n++;
            if (!fputcsv($f, $line)) {
                ("Can't write line $n: $line");
            }
        }
        fclose($f) or ("Can't close php://output");
        $str = ob_get_contents();
        ob_end_clean();

        if (!$downloadFile) {
            return $str;
        }

        echo $str;
    }
743021
public function decrypt($data) {
        $iv = substr($this->key, 0, 16);
        $decrypted = openssl_decrypt($data, 'AES-256-CBC',
            substr($this->key, 0, 32), OPENSSL_ZERO_PADDING, $iv);

        //去除补位字符
        $result = $this->pkcs7UnPad($decrypted, $this->blockSize);
        //去除16位随机字符串,网络字节序和AppId
        if (strlen($result) < 16) {
            throw new \InvalidArgumentException('LENGTH < 16');
        }
        $content = substr($result, 16, strlen($result));
        $len_list = unpack('N', substr($content, 0, 4));
        $xml_len = $len_list[1];
        $xml_content = substr($content, 4, $xml_len);
        $fromAppId = substr($content, $xml_len + 4);
        if (!$this->appId)
            $this->appId = $fromAppId;
        return $xml_content;
    }
559039
private function _readBIFF5CellRangeAddressFixed($subData)
	{
		// offset: 0; size: 2; index to first row
		$fr = self::_GetInt2d($subData, 0) + 1;

		// offset: 2; size: 2; index to last row
		$lr = self::_GetInt2d($subData, 2) + 1;

		// offset: 4; size: 1; index to first column
		$fc = ord($subData{4});

		// offset: 5; size: 1; index to last column
		$lc = ord($subData{5});

		// check values
		if ($fr > $lr || $fc > $lc) {
			throw new PHPExcel_Reader_Exception('Not a cell range address');
		}

		// column index to letter
		$fc = PHPExcel_Cell::stringFromColumnIndex($fc);
		$lc = PHPExcel_Cell::stringFromColumnIndex($lc);

		if ($fr == $lr and $fc == $lc) {
			return "$fc$fr";
		}
		return "$fc$fr:$lc$lr";
	}
855379
public function update(array $data = [])
    {
        $options = $this->parseExpress();
        $data    = array_merge($options['data'], $data);
        $pk      = $this->getPk($options);
        $where   = [];
        if (isset($options['cache']) && is_string($options['cache']['key'])) {
            $key = $options['cache']['key'];
        }

        if (empty($options['where'])) {
            // 如果存在主键数据 则自动作为更新条件
            if (is_string($pk) && isset($data[$pk])) {
                $where[$pk] = $data[$pk];
                if (!isset($key)) {
                    $key = 'think:' . $options['table'] . '|' . $data[$pk];
                }
                unset($data[$pk]);
            } elseif (is_array($pk)) {
                // 增加复合主键支持
                foreach ($pk as $field) {
                    if (isset($data[$field])) {
                        $where[$field] = $data[$field];
                    } else {
                        // 如果缺少复合主键数据则不执行
                        throw new Exception('miss complex primary data');
                    }
                    unset($data[$field]);
                }
            }
            if (!isset($where)) {
                // 如果没有任何更新条件则不执行
                throw new Exception('miss update condition');
            } else {
                $options['where']['AND'] = $where;
            }
        } elseif (!isset($key) && is_string($pk) && isset($options['where']['AND'][$pk])) {
            $key = $this->getCacheKey($options['where']['AND'][$pk], $options, $this->bind);
        }

        //过滤无效字段
        $this->filter($data);

        // 生成UPDATE SQL语句
        $sql = $this->builder->update($data, $options);
        // 获取参数绑定
        $bind = $this->getBind();
        if ($options['fetch_sql']) {
            // 获取实际执行的SQL语句
            return $this->connection->getRealSql($sql, $bind);
        } else {
            // 执行操作
            $result = '' == $sql ? 0 : $this->execute($sql, $bind);
            if ($result) {
                if (is_string($pk) && isset($where[$pk])) {
                    $data[$pk] = $where[$pk];
                } elseif (is_string($pk) && isset($key) && strpos($key, '|')) {
                    list($a, $val) = explode('|', $key);
                    unset($a);
                    $data[$pk]     = $val;
                }
                $options['data'] = $data;
                $this->trigger('after_update', $options);
            }
            return $result;
        }
    }
205941
public function copyFrom($data)
    {
        if (is_array($data) || ($data instanceof \Traversable)) {
            if ($this->_count > 0) {
                $this->clear();
            }
            if ($data instanceof CList) {
                $data = $data->_data;
            }
            foreach ($data as $item) {
                $this->push($item);
            }
        } elseif ($data !== null) {
            throw new Exception('实例化列表参数必须是数组或可遍历的对象', 100100501);
        }
    }
1272819
public static function arrayToXLS(Array $data, String $file = 'excel.xls')
    {
        $file = Base::suffix($file, '.xls');

        header("Content-Disposition: attachment; filename=\"$file\"");
        header("Content-Type: application/vnd.ms-excel;");
        header("Pragma: no-cache");
        header("Expires: 0");

        $output = fopen("php://output", 'w');

        foreach( $data as $column )
        {
            fputcsv($output, $column, "\t");
        }

        fclose($output);
    }
175865
public function mergeWith($data)
    {
        if (is_array($data) || ($data instanceof \Traversable)) {
            if ($data instanceof CList) {
                $data = $data->_data;
            }
            foreach ($data as $item) {
                $this->push($item);
            }
        } elseif ($data !== null) {
            throw new Exception('列表合并参数必须是数组或可遍历的对象', 100100502);
        }
    }
152046
public static function encode($data)
    {
        $module = $data['module'];
        $interface = $data['interface'];
        $cost_time = $data['cost_time'];
        $success = $data['success'];
        $code = isset($data['code']) ? $data['code'] : 0;
        $msg = isset($data['msg']) ? $data['msg'] : '';
        
        // 防止模块名过长
        if(strlen($module) > self::MAX_CHAR_VALUE)
        {
            $module = substr($module, 0, self::MAX_CHAR_VALUE);
        }

        // 防止接口名过长
        if(strlen($interface) > self::MAX_CHAR_VALUE)
        {
            $interface = substr($interface, 0, self::MAX_CHAR_VALUE);
        }

        // 防止msg过长
        $module_name_length = strlen($module);
        $interface_name_length = strlen($interface);
        $avalible_size = self::MAX_UDP_PACKGE_SIZE - self::PACKAGE_FIXED_LENGTH - $module_name_length - $interface_name_length;
        if(strlen($msg) > $avalible_size)
        {
            $msg = substr($msg, 0, $avalible_size);
        }

        // 打包
        return pack('CCfCNnN', $module_name_length, $interface_name_length, $cost_time, $success ? 1 : 0, $code, strlen($msg), time()).$module.$interface.$msg;
    }
366008
function type(data) {
      var result = [];
      for (var i = 0; i < data.values.length; i++) {
        var day = new Date(defaultYear + '-' + data.axisX[i]).getDay();
        var isWeekend = (day == 6 || day == 0) ? true : false;
        // object
        var o = {
          xAxis: data.axisX[i],
          isWeekend: isWeekend,
          all: ALL_MINUTE
        };

        var originData = data.values[i];
        var newData;
        if (typeof originData == 'string') {
          newData = originData.trim().split(' ');
        } else {
          newData = originData;
        }
        var len = newData.length;
        if (len >= 2) {
          var arr1 = newData[0].split(':');
          var arr2 = newData[len - 1].split(':');
          var t1 = parseInt(arr1[0]) * 60 + parseInt(arr1[1]); // 上班打卡时间
          var t2 = parseInt(arr2[0]) * 60 + parseInt(arr2[1]); // 下班打卡时间

          var AMBefore = 0; // 休息时间
          var AMOver = 0; // 预备时间,(超过阈值当作加班时间)
          var AMRest = 0; // 上午休息时间
          var AMLate = 0; // 上午迟到时间
          var AMWork = 0; // 上午工作时间
          var AMEarly = 0; // 上午早退时间

          var PMRest = 0; // 午休时间
          var PMLate = 0; // 下午迟到时间
          var PMWork = 0; // 下午工作时间
          var PMEarly = 0; // 下午早退时间
          var PMOver = 0; // 加班时间，非正常情况下特殊加班用
          var PMAfter = 0; // 休息时间

          if (t2 <= elasticFirst) {
            AMBefore = t1;
            AMOver = t2 - t1;
            AMRest = HALF_MINUTE - t2;
            AMLate = 0;
            AMWork = 0;
            AMEarly = 0;

            PMRest = 0;
            PMLate = 0;
            PMWork = 0;
            PMEarly = 0;
            PMOver = 0;
            PMAfter = HALF_MINUTE;
          } else if (t2 <= HALF_MINUTE) {
            AMBefore = t1;
            if (t1 < elasticFirst) {
              AMOver = elasticFirst - t1;
            } else {
              AMOver = 0;
            }
            AMRest = 0;
            if (t1 > elasticLatest) {
              AMLate = t1 - elasticLatest;
            } else {
              AMLate = 0;
            }
            if (t1 <= elasticFirst) {
              AMWork = t2 - elasticFirst;
            } else if (t1 > elasticFirst) {
              AMWork = t2 - t1;
            } else {
              AMWork = 0;
            }
            AMEarly = HALF_MINUTE - t2;

            PMRest = 0;
            PMLate = 0;
            PMWork = 0
            PMEarly = 0;
            PMOver = 0;
            PMAfter = HALF_MINUTE;
          } else if (t2 <= AFTERNOON_START && t1 >= HALF_MINUTE) {
            AMBefore = HALF_MINUTE;
            AMOver = 0;
            AMRest = 0;
            AMLate = 0;
            AMWork = 0;
            AMEarly = 0;
            PMRest = restMinute;
            PMLate = 0;
            PMWork = 0;
            PMEarly = 0;
            PMOver = 0;
            PMAfter = HALF_MINUTE - restMinute;
          } else if (t1 >= HALF_MINUTE) {
            AMBefore = HALF_MINUTE;
            AMOver = 0;
            AMRest = 0;
            AMLate = 0;
            AMWork = 0;
            AMEarly = 0;
            PMRest = restMinute;
            PMLate = t1 > AFTERNOON_START ? (t1 - AFTERNOON_START) : 0;
            PMWork = (t2 - (t1 < AFTERNOON_START ? AFTERNOON_START : t1) >= workMinute) ? workMinute : (t2 - (t1 < AFTERNOON_START ? AFTERNOON_START : t1));
            PMEarly = (t2 < AFTERNOON_FIRST) ? (AFTERNOON_FIRST - t2) : 0;
            PMOver = (PMWork < workMinute) ? 0 : (t2 - (t1 < AFTERNOON_START ? AFTERNOON_START : t1) - workMinute);
            PMAfter = ALL_MINUTE - (t2 < AFTERNOON_START ? AFTERNOON_START : t2) - PMEarly;
          } else if (t1 >= AFTERNOON_LATEST) {
            AMBefore = HALF_MINUTE;
            AMOver = 0;
            AMRest = 0;
            AMLate = 0;
            AMWork = 0;
            AMEarly = 0;
            PMRest = HALF_MINUTE - PMOver - PMAfter;
            PMLate = 0;
            PMWork = 0;
            PMEarly = 0;
            PMOver = t2 - t1;
            PMAfter = ALL_MINUTE - t2;
          } else {
            AMOver = t1 > elasticFirst ? 0 : (elasticFirst - t1);
            AMRest = 0;
            AMLate = t1 < elasticLatest ? 0 : t1 - elasticLatest;
            AMWork = HALF_MINUTE - (t1 >= elasticFirst ? t1 : elasticFirst);
            AMEarly = 0;
            AMBefore = t1 - AMLate;

            PMRest = restMinute;
            PMLate = 0;
            if (t2 < AFTERNOON_START) {
              PMWork = 0;
            } else {
              var temp = t2 - (t1 < elasticFirst ? elasticFirst : t1) - restMinute;
              PMWork = temp > workMinute ? (workMinute - AMWork) : (temp - AMWork);
            }
            if (t2 < AFTERNOON_LATEST) {
              PMEarly = workMinute - AMWork - PMWork;
            } else {
              PMEarly = 0;
            }
            PMOver = (t2 - (t1 < elasticFirst ? elasticFirst : t1) - restMinute - workMinute) > 0 ? (t2 - (t1 < elasticFirst ? elasticFirst : t1) - restMinute - workMinute) : 0;
            PMAfter = ALL_MINUTE - (t2 < AFTERNOON_START ? AFTERNOON_START : t2) - PMEarly;
          }

          o[STACK_LABEL[0]] = AMBefore;
          o[STACK_LABEL[1]] = AMOver;
          o[STACK_LABEL[2]] = AMRest;
          o[STACK_LABEL[3]] = AMLate;
          o[STACK_LABEL[4]] = AMWork;
          o[STACK_LABEL[5]] = AMEarly;
          o[STACK_LABEL[6]] = PMRest;
          o[STACK_LABEL[7]] = PMLate;
          o[STACK_LABEL[8]] = PMWork;
          o[STACK_LABEL[9]] = PMEarly;
          o[STACK_LABEL[10]] = PMOver;
          o[STACK_LABEL[11]] = PMAfter;
          console.log((AMBefore + AMOver+ AMRest + AMLate + AMWork + AMEarly) == (PMAfter + PMOver + PMRest + PMLate + PMWork + PMEarly));
          result.push(o);
        } else {
          o[STACK_LABEL[0]] = HALF_MINUTE;
          o[STACK_LABEL[1]] = 0;
          o[STACK_LABEL[2]] = 0;
          o[STACK_LABEL[3]] = 0;
          o[STACK_LABEL[4]] = 0;
          o[STACK_LABEL[5]] = 0;
          o[STACK_LABEL[6]] = 0;
          o[STACK_LABEL[7]] = 0;
          o[STACK_LABEL[8]] = 0;
          o[STACK_LABEL[9]] = 0;
          o[STACK_LABEL[10]] = 0;
          o[STACK_LABEL[11]] = HALF_MINUTE;
          result.push(o);
        }
      }
      return result;
    }
622315
private function createSearchData()
    {
        $search_data = [];
        $files = $this->files;
        // 单页文件不解析
        foreach ($files as $key => $file) {
            if (in_array($file['page_uuid'], $this->single_pages)) {
                unset($files[$key]);
                continue;
            }
            $full_content = $this->fileSys->getContent($file['file_path'])['content'];
            // $desc_content = mb_substr($full_content, 0, 1000, 'utf-8');
            // $file['description'] = $this->markd2html->makeHtml( $desc_content );
            $search_data[] = [
                'title' => $file['title'],
                'href' => $file['href'],
                'date' => $file['date'],
                'tags' => implode(',', $file['tags']),
                'type' => implode(',', $file['type']),
                // 'desc' => $file['description'],
            ];
        }
        $file_path = $this->public_dir . DIRECTORY_SEPARATOR . 'articles/data.json';
        $html = json_encode($search_data, JSON_UNESCAPED_UNICODE);
        $this->fileSys->create($file_path, $html);
    }
1044755
protected function _read_data($data) {
        // 检查字段映射
        if(!empty($this->_map) && C('READ_DATA_MAP')) {
            foreach ($this->_map as $key=>$val){
                if(isset($data[$val])) {
                    $data[$key] =   $data[$val];
                    unset($data[$val]);
                }
            }
        }
        return $data;
    }
1032401
protected function _facade($data) {

        // 检查数据字段合法性
        if(!empty($this->fields)) {
            if(!empty($this->options['field'])) {
                $fields =   $this->options['field'];
                unset($this->options['field']);
                if(is_string($fields)) {
                    $fields =   explode(',',$fields);
                }    
            }else{
                $fields =   $this->fields;
            }        
            foreach ($data as $key=>$val){
                if(!in_array($key,$fields,true)){
                    unset($data[$key]);
                }elseif(array_key_exists($key,$this->mapFields)){
                    // 需要处理映射字段
                    $data[$this->mapFields[$key]] = $val;
                    unset($data[$key]);
                }
            }
        }
       
        // 安全过滤
        if(!empty($this->options['filter'])) {
            $data = array_map($this->options['filter'],$data);
            unset($this->options['filter']);
        }
        $this->_before_write($data);
        return $data;
     }
1107457
private function init($data=null)
    {
        if (!is_null($this->stack)) return $this;
        
        if (!is_null($data))  $this->data = $data;
        if (!is_array($this->data) || empty($this->data)) return $this;
        
        // 先转为 id 为键的数据
        $t_data = array();
        $pids   = array();
        foreach ($this->data as $k => $v) {
            if (!isset($v[$this->fields[0]])) {
                throw new \InvalidArgumentException('tree fields error:' . implode(',', $this->fields));
                break; // 如果数组结构不符合，跳过
            }
            $t_data[$v[$this->fields[0]]] = $v;
            $pids[$v[$this->fields[1]]] = $v[$this->fields[1]];
        }
        $this->data = & $t_data;
        
        // 修正root，当parent_id=root不存在时取最小的parent_id作为root
        if (!isset($pids[$this->root])) {
            ksort($pids);
            $this->root = array_keys($pids)[0];
        }
        
        // 先生成父子级的二维的数组
        foreach ($this->data as $node) {
            $this->stack[$node[$this->fields[1]]][$node[$this->fields[0]]] = $node;
        }
        
        
        // 递归遍历生成 完整的带有 items 的数组
        foreach ($this->stack as $k => $v) {
            $this->handleStackElement($k);
        }
        //print_r($this->stack);exit;
    }