<?php

/**
 * @file
 *
 * 常用函数
 */

use Pyramid\Component\Database\Database;
use Pyramid\Component\Password\Password;
use Pyramid\Component\Utility\Xss;
use Pyramid\Component\Utility\StringTool;
use Pyramid\Component\Utility\IpHelper;
use Pyramid\Component\Route\Route;
use Pyramid\Component\Uuid\Uuid;
use Pyramid\Component\Permission\Permission;
use Pyramid\Component\Redis\Connection as RedisConnection;
use Pyramid\Vendor\Pinyin\Pinyin;
use Pyramid\Component\Image\Captcha;
use Pyramid\Component\Reflection\ReflectionClass;

//注册权限
function permission_register($permission, array $permissions = array()) {
    Permission::register($permission, $permissions);
}

//获取权限
function permission_get($permission = null) {
    return Permission::get($permission);
}

//注册route
function route_register($route, $callback) {
    Route::register($route, $callback);
}

//匹配route
function route_match($path) {
    return Route::match($path);
}

//获取route
function route_get($route) {
    return Route::get($route);
}

//删除route
function route_delete($route) {
    return Route::delete($route);
}

//设置Redis配置
function redis_config($target, array $config = array()) {
    RedisConnection::setConfig($target, $config);
}

//获取redis实例
function redis($target = 'default') {
    return RedisConnection::getConnection($target);
}

//增强型var_export
function pyramid_var_export($var, $return = false, $prefix = '') {
    static $func = __FUNCTION__;
    if (is_array($var)) {
        if (empty($var)) {
            $output = 'array()';
        } else {
            $output = "array(\n";
            foreach ($var as $key => $value) {
                $output .= '  ' . $func($key, true) . ' => ' . $func($value, true, '  ') . ",\n";
            }
            $output .= ')';
        }
    } elseif (is_bool($var)) {
        $output = $var ? 'true' : 'false';
    } elseif (is_string($var)) {
        if (strpos($var, "\n") !== false || strpos($var, "'") !== false) {
            $var = str_replace(array('\\', '"', "\n", "\r", "\t"), array('\\\\', '\"', '\n', '\r', '\t'), $var);
            $output = '"' . $var . '"';
        } else {
            $output = "'" . $var . "'";
        }
    } elseif (is_object($var) && get_class($var) === 'stdClass') {
        $output = '(object) ' . $func((array) $var, true, $prefix);
    } else {
        $output = var_export($var, true);
    }

    if ($prefix) {
        $output = str_replace("\n", "\n$prefix", $output);
    }
    
    if ($return) {
        return $output;
    } else {
        echo $output;
    }
}

//随机函数
function random($length = 6, $chars = '0123456789') {
    $hash = '';
    $max  = strlen($chars) - 1;
    while ($length-- && $length >= 0) {
        $hash .= $chars[mt_rand(0, $max)];
    }
  
    return $hash;
}

//格式化大小
function get_size($size, $dec = 2) {
    $units = array('B','K','M','G','T','P','E','Z','Y');
	$count = 0;
	while ($size >= 1024) {
		$size /= 1024;
		$count++;
	}
    
	return round($size,$dec) . ' '. $units[$count];
}

//常用格式获取
function get_ext($file, $default = '', $origext = '') {
    $f = fopen($file, 'rb');
    $bin = fread($f, 2);
    fclose($f);
    $str  = @unpack('C2chars', $bin);
    $code = intval($str['chars1'] . $str['chars2']);
    $file_ext = $origext ? $origext : strtolower(strrchr($file, '.'));
    $file_ext = trim($file_ext, '.');
    $ext  = '';
    switch ($code) {
        case 7790:  $ext = 'exe';   break;
        case 7784:  $ext = 'midi';  break; //4D546864
        case 8297:  $ext = 'rar';   break; //52617221
        case 55122: $ext = '7z';    break; //377ABCAF271C
        case 255216:$ext = 'jpg';   break; //FFD8FF
        case 7173:  $ext = 'gif';   break; //47494638
        case 6677:  $ext = 'bmp';   break; //424D
        case 13780: $ext = 'png';   break; //89504E47
        case 8273:  $ext = 'webp';  break;
        case 5666:  $ext = 'psd';   break; //38425053
        case 6586:  $ext = 'avi';   break; //41564920
        case 8765:  $ext = 'wav';   break; //57415645
        case 109111:$ext = 'mov';   break; //6D6F6F76
        case 6567:  $ext = 'dwg';   break; //41433130
        case 7373: case 7777: $ext = 'tif'; break; //49492A00
        case 197208: $ext = 'eps';  break;
        case 3780:
            if ($file_ext == 'pdf') {
                $ext = $file_ext;
            } else {
                $ext = 'ai';
            }
            break;
        case 8075: //504B0304 docx|xlsx|pptx也是zip
            if ($file_ext == 'docx' || $file_ext == 'xlsx' || $file_ext == 'pptx') {
                $ext = $file_ext;
            } else {
                $ext = 'zip';
            }
            break;
    }
    if ($str['chars1'] == '-1' && $str['chars2'] == '-40') {
        $ext = 'jpg';
    } elseif ($str['chars1'] == '-119' && $str['chars2'] == '80') {
        $ext = 'png';
    }

    return $ext ? $ext : $default;
}

//是否运行在cli模式
function is_cli() {
  return (!isset($_SERVER['SERVER_SOFTWARE']) 
           && (PHP_SAPI == 'cli' || (is_numeric($_SERVER['argc']) && $_SERVER['argc'] > 0)));
}

//是否是UTF8编码
function is_utf8($text) {
    return StringTool::isUTF8($text);
}

//是否为合法email地址
function is_email($email) {
    return StringTool::isEmail($email);
}

//是否为合法手机号
function is_mobile($mobile = '') {
    return preg_match("/^1[34578]\d{9}$/", $mobile);
}

//替换一次
function str_replace_once($needle, $replace, $haystack) {
    $pos = strpos($haystack, $needle);
    if ($pos === false) {
        return $haystack;
    }
    return substr_replace($haystack, $replace, $pos, strlen($needle));
}

//IP是否在指定列表
function is_validated_ip($ip, $whiteList = array(), $blackList = array()) {
    return IpHelper::check($ip, $whiteList, $blackList);
}

//Xss过滤
function xss_filter($string, $allowedTags = array(), $allowedStyleProperties = array()) {
    static $xss;
    if (!isset($xss)) {
        $xss = new Xss();
    }
    return $xss->filter($string, $allowedTags, $allowedStyleProperties);
}

//Xss去除(用户搜索表单展示关键词时)
function xss_clean($string, $urlcode = true) {
    if ($urlcode) {
        $string = urldecode($string);
    }
    $string = xss_filter($string);
    $string = preg_replace("/[\\x00-\\x08\\x0b-\\x0c\\x0e-\\x1f]/u", '', $string);
    $string = str_replace(array('<','>','"',"'",'&'), '', $string);
    return htmlspecialchars($string, ENT_QUOTES, 'UTF-8');
}

//组装树结构
function data_to_tree($data, $root = 0, $pid = 'parent', $child = 'child', $dendriform = false) {
    $tree  = array();
    $unset = array();
    foreach ($data as $tid => $v) {
        $parentId = $v[$pid];
        if ($root == $parentId) {
            $tree[] = &$data[$tid];
        } elseif (isset($data[$parentId])) {
            $data[$parentId][$child][] = &$data[$tid];
            $unset[] = $tid;
        }
    }
    if (!$tree && $dendriform) {
        foreach($unset as $tid) {
            unset($data[$tid]);
        }
        return $data;
    }
    return $tree;
}

//给定一个数字,转化为包含2^N的数组
function number_to_bin($n) {
    $return = array();
    if ($n <= 0) {
        return (array) $n;
    }
    $i = 1;
    while ($i <= $n) {
        if ($i & $n) {
            $return[] = $i;
        }
        $i *= 2;
    }

    return $return;
}

//uuid
function uuid() {
    return Uuid::generate();    
}

//是否为uuid格式
function is_uuid($uuid) {
    return Uuid::isValid($uuid);    
}

//file scan
function file_scan($dir, $regx, $options = array(), $depth = 1) {
    $options += array(
        'nomask'   => '/(\.\.?|CSV)$/',
        'recurse'  => true,
        'minDepth' => 1,
        'maxDepth' => 10,
        'fullpath' => false,
    );
    $files = array();
    if (is_dir($dir) && $depth <= $options['maxDepth'] && ($handle = opendir($dir))) {
        while (false !== ($filename = readdir($handle))) {
            if (!preg_match($options['nomask'], $filename) && $filename[0] != '.') {
                $subdir = $dir . '/' . $filename;
                if (is_dir($subdir) && $options['recurse']) {
                    $files = array_merge(file_scan($subdir, $regx, $options, $depth + 1), $files);
                } elseif ($depth >= $options['minDepth']) {
                    if (preg_match($regx, $filename) || ($options['fullpath'] && preg_match($regx, $subdir))) {
                        $files[] = array(
                            'dirname'  => $dir,
                            'basename' => $filename,
                            'file'     => $dir . '/' . $filename,
                        );
                    }
                }
            }
        }
        closedir($handle);
    }
    return $files;
}

//file scan & include
function file_include($dir, $regx, $options = array()) {
    $files = file_scan($dir, $regx, $options);
    foreach ($files as $f) {
        require_once $f['file'];
    }
    return $files;
}

//curl
function curl($url, $headers = array(), $params = array(), $proxy = '', $option = array()) {
    $header = array();
    $headers += array('Expect' => '');
    foreach ($headers as $k => $v) {
        $header[] = $k . ': ' . $v;
    }
    $url = $proxy ? $proxy . urlencode($url) : $url;
    $ch = curl_init();
    $option += array(
        CURLOPT_URL             => $url,
        CURLOPT_HTTPHEADER      => $header,
        CURLOPT_HEADER          => true,
        CURLOPT_FOLLOWLOCATION  => true,
        CURLOPT_MAXREDIRS       => 8,
        CURLOPT_RETURNTRANSFER  => true,
        CURLOPT_CONNECTTIMEOUT  => 10,
        CURLOPT_TIMEOUT         => 30,
    );
    if (!empty($params)) {
        if (empty($option['CURLOPT_CUSTOMREQUEST'])) {
            $option[CURLOPT_POST] = true;
        }
        if (is_array($params) && (isset($params['file']) || isset($params['upfile']) || isset($params['media']))) {
            $option[CURLOPT_POSTFIELDS] = $params;
        }
        elseif (is_array($params) || is_object($params)) {
            $option[CURLOPT_POSTFIELDS] = http_build_query($params);
        } else {
            $option[CURLOPT_POSTFIELDS] = $params;
        }
    }
    if (stripos($url, 'https') === 0) {
        //$port = parse_url($url, PHP_URL_PORT);
        //$option[CURLOPT_PORT] = $port ? $port : 443;
        $option[CURLOPT_SSL_VERIFYPEER] = false;
        $option[CURLOPT_SSL_VERIFYHOST] = false;
    }
	if (class_exists('\CURLFile')) {
		curl_setopt($ch, CURLOPT_SAFE_UPLOAD, true);
	} elseif (defined('CURLOPT_SAFE_UPLOAD')) {
		curl_setopt($ch, CURLOPT_SAFE_UPLOAD, false);
	}
    curl_setopt_array($ch, $option);
    $content = curl_exec($ch);
    $errno = curl_errno($ch);
    if ($errno > 0) {
        $content = "HTTP/1.1 501 ERROR({$errno}): " . curl_error($ch) . "\r\n\r\n";
    }
    curl_close($ch);
    return explode("\r\n\r\n", $content, 2);
}

//string的value...
function java_arg(array $args) {
    static $func = __FUNCTION__;
    foreach ($args as $k => $v) {
        switch (gettype($v)) {
            case 'string':
                break;
            case 'integer':
            case 'double':
                $args[$k] = (string) $v;
                break;            
            case 'array':
                $args[$k] = $func($v);
                break;
            case 'object':
                $args[$k] = $func((array) $v);
                break;
            case 'boolean':                          
            case 'resource':
            case 'null':
                unset($args[$k]);
                break;
            default:
                unset($args[$k]);
        }
    }

    return $args;
}

//高亮
function highlight(&$source, $words, $element = 'highlight') {
    static $func = __FUNCTION__;
    if (is_scalar($source)) {
        $regexp = '/(' . preg_replace('/\s+/', '|', preg_quote($words,'/')) . ')/iu';
        $source = preg_replace($regexp, '<'.$element.'>$1</'.$element.'>', $source);
    } elseif (is_array($source)) {
        foreach ($source as $k => $v) {
            $func($source[$k], $words, $element);
        }
    } elseif (is_object($source)) {
        foreach ($source as $k => $v) {
            $func($source->$k, $words, $element);
        }
    }
    return $source;
}

//获取数组或对象的唯一标识
function identity($value) {
    static $func = __FUNCTION__;
    if (is_object($value)) {
        $value = (array) $value;
    } else if (!is_array($value)) {
        $value = array($value);
    }
    ksort($value);
    $tmp = '';
    foreach ($value as $k=>$v) {
        if (is_array($v) || is_object($v)) {
            $tmp .= $k . $func($v);
        } else {
            $tmp .= $k . (string) $v;
        }
    }

    return md5($tmp);
}

//生成一个流水号
function uniquesn($prefix = '') {
    list ($usec, $sec) = explode(' ', microtime());
    return $prefix . date('YmdHis', $sec) . sprintf('%06d',$usec * 1000000);
}

//中文拼音
/*
PINYIN_TONE 	    UNICODE 式音调：měi hǎo
PINYIN_ASCII_TONE 	带数字式音调： mei3 hao3
PINYIN_NO_TONE 	    无音调：mei hao
PINYIN_KEEP_NUMBER 	保留数字
PINYIN_KEEP_ENGLISH 保留英文
PINYIN_KEEP_PUNCTUATION 保留标点
PINYIN_UMLAUT_V     使用 v 代替 yu, 例如：吕 lyu 将会转为 lv

->convert($string, $option = PINYIN_DEFAULT)
->name($stringName, $option = PINYIN_NAME)  姓名转拼音
->permalink($string, $delimiter = '-', $option = PINYIN_DEFAULT)
->abbr($string, $delimiter = '', $option = PINYIN_DEFAULT)
->phrase($string, $delimiter = ' ', $option = PINYIN_DEFAULT)
->sentence($string, $delimiter = ' ', $option = \PINYIN_NO_TONE)
*/
function pinyin() {
    static $py;
    if (!isset($py)) {
        $py = new Pinyin();
    }
    return $py;
}

//兼容CryptoJs.AES的加密
function cryptojs_aes_encrypt($data, $key = LICENSE, $iv = null) {
    if (extension_loaded('mcrypt')) {
        if (is_null($iv)) { $iv = $key; }
        $key = md5($key);
        $iv  = md5($iv);
        $key = pack('H*', $key);
        $iv  = pack('H*', $iv);
        if (is_array($data) || is_object($data)) {
            $data = json_encode($data);
        }
        $encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $data, MCRYPT_MODE_CBC, $iv);
        return base64_encode($encrypted);
    } else {
        if (strlen($data) % 16) {
            $data = str_pad($data, strlen($data)+16-strlen($data)%16,"\0");
        }
        $encrypted = openssl_encrypt($data, 'AES-128-CBC', md5($key,true), OPENSSL_NO_PADDING, md5($iv ? $iv : $key,true));
        return base64_encode($encrypted);
    }
}

//兼容CryptoJs.AES的解密
function cryptojs_aes_decrypt($encrypted, $key = LICENSE, $iv = null) {
    if (extension_loaded('mcrypt')) {
        if (is_null($iv)) { $iv = $key; }
        $key = md5($key);
        $iv  = md5($iv);
        $key = pack('H*', $key);
        $iv  = pack('H*', $iv);
        $encrypted = base64_decode($encrypted);
        $decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $encrypted, MCRYPT_MODE_CBC, $iv);
        return trim($decrypted);
    } else {
        $decrypted = openssl_decrypt(base64_decode($encrypted), 'AES-128-CBC', md5($key,true), OPENSSL_NO_PADDING, md5($iv ? $iv : $key,true));
        $decrypted = rtrim(rtrim($decrypted, chr(0)), chr(7));
        return $decrypted;
    }
}

//CBC加密
function cbc_encrypt($str, $iv = '', $key = LICENSE) {
    $key = base64_decode($key);
    $str = trim($str);
    $str = add_PKCS7_Padding($str);
    $iv = $iv ? base64_decode($iv) : str_repeat("\0", 16);
    $encrypt_str = openssl_encrypt($str, 'aes-128-cbc', $key, OPENSSL_NO_PADDING, $iv);
    return base64_encode($encrypt_str);
}

//CBC解密
function cbc_decrypt($str, $iv = '', $key = LICENSE) {
    $str = base64_decode($str);
    $key = base64_decode($key);
    $iv = $iv ? base64_decode($iv) : str_repeat("\0", 16);
    $decrypt_str = openssl_decrypt($str, 'aes-128-cbc', $key, OPENSSL_NO_PADDING, $iv);
    $decrypt_str = strip_PKSC7_Padding($decrypt_str);
    return $decrypt_str;
}

//填充算法
function add_PKCS7_Padding($source) {
    $source = trim($source);
    $block = 16;

    $pad = $block - (strlen($source) % $block);
    if ($pad <= $block) {
        $char = chr($pad);
        $source .= str_repeat($char, $pad);
    }
    return $source;
}

//移去填充算法
function strip_PKSC7_Padding($source) {
    $char = substr($source, -1);
    $num = ord($char);
    if ($num == 62) return $source;
    $source = substr($source, 0, -$num);
    return $source;
}

//验证码图片base64
function captcha($captcha, $format = 'base64', $options = array()) {
    $im = new Captcha($options);
    return $im->generate($captcha, $format);
}

/**
 * ===============================
 * 一些类似array_函数的object_操作
 * ===============================
 */

//合并两个对象的键值
function object_merge($object1, $object2) {
    return (object) ((array) $object1 + (array) $object2);
}

//获取对象中指定keys的values
function object_intersect_key($object, $keys = array()) {
    //没有定义keys,直接返回
    if (empty($keys)) {
        return $object;
    }
    //解析需要的keys和层级,字段信息
    $needs = array();
    foreach ($keys as $key) {
        preg_match('|(?<key>\w+)(?<num>\[\d*\])?(?<fields>\([\w,]+\))?|', $key, $match);
        $needs[$match['key']] = $match;
    }
    //转换为array
    $data = (array) $object;
    foreach ($data as $k => $v) {
        if (isset($needs[$k])) {
            //有[],则认为是关联数组
            if (isset($needs[$k]['num']) && $needs[$k]['num']) {
                $length = trim($needs[$k]['num'], '[]');
                if ($length) {
                    $data[$k] = array_slice($v, 0, $length);
                }
                if (isset($needs[$k]['fields'])) {
                    $ks = explode(',', trim($needs[$k]['fields'],'()'));
                    foreach ($data[$k] as $kk => $vv) {
                        $data[$k][$kk] = array_intersect_key($vv, array_flip($ks));
                    }
                }
            }
            //无[],则认为是索引数组
            elseif (isset($needs[$k]['fields'])) {
                $ks = explode(',', trim($needs[$k]['fields'],'()'));
                $data[$k] = array_intersect_key($v, array_flip($ks));
            }            
        } else {
            unset($data[$k]);
        }
    }
    
    return (object) $data;
}

//获取PHP是32位还是64位
function get_php_int_size() {
    return PHP_INT_SIZE == 4 ? 32 : 64;
}

/**
 * ========================
 * 一些兼容高版本PHP的函数
 * ========================
 */

/**
 * array_column (php5.5)
 */
function pyramid_array_column($input, $columnKey, $indexKey = null) {
    $return = array();
    if (!is_array($input)) {
        return $return; 
    }
    if ($indexKey === null) {
        foreach ($input as $v) {
            if (is_object($v) && isset($v->$columnKey)) {
                $return[] = $v->$columnKey;
            } elseif (isset($v[$columnKey])) {
                $return[] = $v[$columnKey];
            }
        }
    } else {
        foreach ($input as $v) {
            if (isset($v[$columnKey])) {
                $return[$v[$indexKey]] = $v[$columnKey];
            }
        }
    }
    
    return $return;
}
if (!function_exists('array_column')) {
    function array_column(array $input, $columnKey, $indexKey = null) {
        return pyramid_array_column($input, $columnKey, $indexKey);
    }
}

/**
 * password_hash (php5.5)
 */
function pyramid_password_hash($password, $algo = 1, $options = array()) {
    return Password::hash($password);
}

/**
 * password_verify (php5.5)
 */
function pyramid_password_verify($password, $hash) {
    return Password::verify($password, $hash);
}

/**
 * password_needs_rehash (php5.5)
 */
function pyramid_password_needs_rehash($hash, $algo = 1) {
    return Password::needsRehash($hash);
}

/**
 * gzdecode (php5.4)
 */
if (!function_exists('gzdecode')) {
    function gzdecode($data) {
        return gzinflate(substr($data,10,-8)); 
    }
}

/**
 * 注册应用模块
 */
function pyramid_registe_module($project, $dir, $routing = false, $regx = '|(\w+)/\\1.php$|is', $options = array()) {
    class_loader()->registerNamespace($project, $dir);
    $options += array('fullpath'=>true, 'minDepth'=>2);
    $files = file_include($dir.'/'.$project, $regx, $options);
    if ($routing) {
        foreach ($files as $f) {
            list ($module,) = explode('.', $f['basename']);
            $r = new ReflectionClass("{$project}\\{$module}\\{$module}");
            foreach ($r->getMethods() as $method=>$m) {
                if (!empty($m['comments']['route'])) {
                    $routes = $m['comments']['route'];
                    if (!empty($m['comments']['access'])) {
                        route_register($routes, array(
                            'callback' => "{$project}\\{$module}\\{$module}::{$method}",
                            'access'   => $m['comments']['access'],
                            'comments' => $m['comments'],
                        ));
                    } else {
                        route_register($routes, array(
                            'callback' => "{$project}\\{$module}\\{$module}::{$method}",
                            'comments' => $m['comments'],
                        ));
                    }
                }
            }
        }
    }
}

/**
 * Phar打包
 * filename 生成的文件
 * src:[directory,pattern]
 */
function pyramid_phar($filename, $src, $stub = 'index.php', $compress = true) {
    $phar = new Phar($filename);
    if (is_string($src)) {
        $phar->buildFromDirectory($src);
    } elseif (is_array($src)) {
        list($directory,$pattern) = $src;
        $phar->buildFromDirectory($directory,$pattern);
    } else {
        return false;
    }
    if ($compress){
        $phar->compressFiles(Phar::GZ);
    }
    $phar->setSignatureAlgorithm(Phar::MD5);
    $phar->stopBuffering();
    if (is_string($stub)) {
        $phar->setDefaultStub($stub);
    } elseif (is_array($stub)) {
        list($cliIndex,$weIndex) = $stub;
        $phar->setDefaultStub($cliIndex, $weIndex);
    }
    return $filename;
}


function pyramid_check_plain($string = '') {
    return StringTool::checkPlain($string);
}

/**
 * 读取CSV文件
 *
 * - 默认用第一行的值作为数组键值
 * - 当指定了mapping，则用mapping中的对照值作为键值(header值=>对照字段)
 * - 若check为true，则header里须包含所有mapping的对照,否则返回false
 *
 * return 非UTF-8编码直接返回 0，失败返回false，正常返回array(mapping=>,header=>,data=>)
 */
function pyramid_csv_read($file, $mapping = array(), $check = false) {
    if(!$file || !is_file($file)) {
        return array();
    }

    $fp = fopen($file, 'r');
    $header = fgetcsv($fp);
    $keylen = count($header);

    if (!is_utf8(implode('',$header))) {
        return 0;
    }

    $header[0] = ltrim($header[0],"\xEF\xBB\xBF");

    if ($check && $mapping) {
        $ik = array_intersect_key($mapping, array_flip($header));
        if (count($mapping) != count($ik)) {
            return false;
        }
    }

    foreach($header as $k=>$v) {
        $header[$k] = isset($mapping[$v]) ? $mapping[$v] : $v;
    }

    $data = array();
    while(false !== $row = fgetcsv($fp)) {
        $c = count($row);
        if ($c > $keylen) {
            $row = array_slice($row, 0, $keylen);
        } elseif ($c < $keylen) {
            for($i=0;$i<$keylen-$c;$i++) {
                $row[] = '';
            }
        }
        $data[] = array_combine($header,$row);
    }
    fclose($fp);

    return array(
        'mapping' => $mapping,
        'header' => $header,
        'data' => $data,
    );
}

/**
 * 输出CSV文件
 *
 * - 不指定file时，则输出文件流，建议先 header('Content-Disposition: attachment;filename=FILE')
 * - 当指定了header，则只以header的键写入
 */
function pyramid_csv_write($file, $data = array(), $header = array(), $bom = false) {
    if (!$file || $file == 'php://output') {
        $file = 'php://output';
    } else {
        $folder = dirname($file);
        if (!is_dir($folder)) {
            mkdir($folder, 0755, true);
        }
    }

    $f = fopen($file, 'wb');
    if ($bom) {
        fwrite($f, "\xEF\xBB\xBF");
    }

    if ($header) {
        fputcsv($f, $header);
        foreach($data as $v) {
            $vv = array_intersect_key((array)$v, $header);
            fputcsv($f, array_merge($header,$vv));
        }
    } else {
        foreach($data as $v) {
            fputcsv($f,(array)$v);
        }
    }
    fclose($f);
}
