LEN

PHP 文件上传服务端接口
<?php error_reporting(0); ini_set('display_errors', '0...
扫描右侧二维码阅读全文
07
2017/07

PHP 文件上传服务端接口

<?php
error_reporting(0);
ini_set('display_errors', '0');

abstract class Receivers
{
    const FILE_HOST_URL = 'http://file1.benfu.com/';
    const GENERIC_PNG = 0;
    const PUSH_POPUP = 1;
    const PUSH_IOS_ICON = 2;
    const PUSH_ANDROID_ICON = 3;

    static $file_index = 0;

    /**
     *  获取file 类型 key
     * @param $type
     * @return string
     */
    public static function getFileTypeKey($type)
    {
        $fileTypeKey = array(
            self::GENERIC_PNG => 'file:generic:png:index', // 通用png命名索引
            self::PUSH_POPUP => 'file:popup:index',
            self::PUSH_IOS_ICON => 'file:icon:ios:index',
            self::PUSH_ANDROID_ICON => 'file:icon:android:index',
        );

        return isset($fileTypeKey[$type]) ? $fileTypeKey[$type] : $fileTypeKey[self::GENERIC_PNG];
    }

    static $whiteIpList = array(
        '126.38.45.118',
        '10.34.61.19',
        '127.0.0.1'
    );

    static $config = array();

    public static function run()
    {
        if (!isset($_POST['to'], $_POST['ip'])) {
            self::_jsonReturn('参数错误', 101);
        }
        $ip_arr = array_map('trim', explode(',', $_POST['ip']));
        if (array_diff($ip_arr, self::$whiteIpList)) {
            self::_jsonReturn('IP未授权', 102);
        }
        if ($_FILES["file"]["error"] > 0) {
            self::_jsonReturn('文件上传失败', 103);
        }

        $to_dir = urldecode($_POST['to']);
        $type = $_POST['type'] ?: self::GENERIC_PNG;

        if (self::PUSH_ANDROID_ICON == $type || self::PUSH_IOS_ICON == $type) { // ios 及 安卓 icon 命名一致性问题
            //ios 安卓 唯一ID工具
            $file_name = self::_devUnqidTool($type, $to_dir);
            if (is_bool($file_name)) {
                self::_jsonReturn('ICON 生成文件名失败', 104);
            }
        } else { // 通用生成文件名方法
            // 获取文件名
            $file_name = self::_getNextFileName($type, $to_dir);
            if (is_bool($file_name)) {
                self::_jsonReturn('生成文件名失败', 105);
            }
        }

        $to_file = $to_dir . $file_name;
        self::_log(array('to_file' => $to_file, 'todir' => $to_dir, 'file_name' => $file_name));
        if (!self::_moveFile($_FILES["file"]["tmp_name"], $to_file)) {
            self::_jsonReturn('移动上传文件失败', 106);
        }

        $return = array(
            'file_url' => self::_getFileUrl($to_file),
            'file_index' => self::$file_index
        );

        self::_jsonReturn('上传成功', 200, $return);
    }

    /**
     * 获取文件url
     * @param $file_addr
     * @return string
     */
    private static function _getFileUrl($file_addr)
    {
        $a2array = explode('/', dirname(__FILE__));
        $b2array = explode('/', $file_addr);

        return self::FILE_HOST_URL . implode('/', array_diff_key($b2array, $a2array));
    }

    /**
     * 移动上传文件
     * @param $tmp_name
     * @param $to_file
     * @return bool
     */
    private static function _moveFile($tmp_name, $to_file)
    {
        try {
            if (file_exists($to_file)) {
                unlink($to_file);
            } else {
                $dir = dirname($to_file);
                if (!file_exists($dir)) {
                    self::_mkdirs($dir);
                }
            }
            return move_uploaded_file($tmp_name, $to_file);
        } catch (\Exception $e) {
            return false;
        }
    }

    /**
     * 根据所属类型获取文件名
     * @param $type
     * @param $to_dir
     * @return string
     */
    private static function _getNextFileName($type, $to_dir)
    {
        $redis_key = self::getFileTypeKey($type);
        if (self::PUSH_ANDROID_ICON == $type || self::PUSH_IOS_ICON == $type) { // ios 及 安卓 icon 图片上传
            $ios_key = self::getFileTypeKey(self::PUSH_IOS_ICON);
            $file_ios_index = self::_redisInstance()->get($ios_key);
            $android_key = self::getFileTypeKey(self::PUSH_ANDROID_ICON);
            $file_android_index = self::_redisInstance()->get($android_key);
            $file_index = $file_android_index > $file_ios_index ? $file_android_index : $file_ios_index; // ios 及 安卓 icon 获取最大的索引ID
        } else {
            $file_index = self::_redisInstance()->get($redis_key) ?: 1000;
        }
        $i = 0;
        while (true) { // 兼容
            $file_name = sprintf(self::_getFileTypeNameNorm($type), $file_index + $i);
            if (!file_exists($to_dir . $file_name)) {
                self::_redisInstance()->set($redis_key, $file_index + $i);
                self::$file_index = $file_index + $i;
                return $file_name;
            }
            if ($i > 1000) {
                return false;
            }
            $i++;
        }
    }

    /**
     * ios 安卓 唯一ID工具
     * @param $type
     * @param $to_dir
     * @return string
     */
    private static function _devUnqidTool($type, $to_dir)
    {
        $unqid = $_POST['unqid'];
        $unqid_key = sprintf('file:push:icon:unqid:%s', $unqid);
        if ($file_index = self::_redisInstance()->get($unqid_key)) { // 判断 unqid存在则直接返回unqid 存储的file_index
            self::$file_index = $file_index;
            return sprintf(self::_getFileTypeNameNorm($type), $file_index);
        }
        // unqid 不存在则生成 file_index 返回生成名
        $file_name = self::_getNextFileName($type, $to_dir);
        if (is_bool($file_name)) {
            self::_jsonReturn('生成文件名失败', 201);
        }
        self::_redisInstance()->setex($unqid_key, 86400, self::$file_index); // icon 唯一key

        return $file_name;
    }

    /**
     * 创建目录
     * @param $path
     * @param int $mod
     * @return bool
     */
    private static function _mkdirs($path, $mod = 0777)
    {
        if (is_dir($path)) {
            return chmod($path, $mod);
        }
        $old = umask(0);
        if (mkdir($path, $mod, true) && is_dir($path)) {
            umask($old);
            return true;
        }
        umask($old);

        return false;
    }

    /**
     * 获取文件
     * @param $type
     * @return string
     */
    private static function _getFileTypeNameNorm($type)
    {
        $file_type_name_norm = array(
            self::GENERIC_PNG => uniqid() . '_%d.png',
            self::PUSH_POPUP => date('Ymd') . '_%d.png',
            self::PUSH_IOS_ICON => '%d.png',
            self::PUSH_ANDROID_ICON => '%d.png',
        );

        return $file_type_name_norm[$type] ?: $file_type_name_norm[self::GENERIC_PNG];
    }

    /**
     * json 返回数据
     * @param string $desc
     * @param int $code
     * @param array $data
     */
    private static function _jsonReturn($desc = '', $code = 200, $data = array())
    {
        header("Content-Type:text/html;charset=utf-8");
        echo json_encode(array('status' => $code, 'desc' => $desc, 'data' => (array)$data));
        exit;
    }

    /**
     * redis 单例
     * @var
     */
    static $redisInstance;

    /**
     *  redis 实例
     * @return bool|redis
     */
    private static function _redisInstance()
    {
        if (!empty(self::$redisInstance)) {
            return self::$redisInstance;
        }
        try {
            $redis = new redis();
            $redis->connect(self::$config['host'], self::$config['port']);
            !empty(self::$config['pwd']) && $redis->auth(self::$config['pwd']);
            $redis->select(self::$config['database']);
            self::$redisInstance = $redis;
        } catch (\Exception $e) {
            self::_log('redis error msg :' . $e->getMessage());
            throw new Exception('redis connet is fail');
        }

        return self::$redisInstance;
    }

    /**
     *  配置
     * @return array
     */
    private static function _configInfo()
    {
        return array(
            'host' => '127.0.0.1',
            'port' => '6379',
            'database' => 0,

            'filePath' => __DIR__ . '/logs/',
            'fileName' => 'push_file_' . date('Ymd') . '.log'
        );
    }

    /**
     * 运行日志,记录运行步骤
     */
    public static function _log($message)
    {
        if (is_array($message)) {
            $message = json_encode($message);
        }

        $message = date(DATE_RFC822) . " - " . $message . "\r\n";

        return self::_addToFile($message);
    }

    /**
     * 写入文件函数
     */
    private static function _addToFile($logMessage)
    {
        self::_fileConf();

        return file_put_contents(self::$config['filePath'] . self::$config['fileName'], $logMessage, FILE_APPEND);
    }

    /**
     * 存储文件策略
     */
    private static function _fileConf()
    {
        //获得配置文件
        if (!file_exists(self::$config['filePath'])) {
            mkdir(self::$config['filePath']);
        }
        if (!file_exists(self::$config['filePath'] . self::$config['fileName'])) {
            touch(self::$config['filePath'] . self::$config['fileName']);
        }

        return;
    }

    /**
     * 初始化配置
     */
    public static function _init()
    {
        self::$config = Receivers::_configInfo();
        self::_log(array(
            'get' => $_GET,
            'post' => $_POST,
            'file' => $_FILES
        ));
    }
}

// begin script
Receivers::_init();
Receivers::run();

客户端发送图片

     /**
     * http上传文件
     * @param $to
     * @param $file_addr
     * @param $url
     * @param $type
     * @param $unqid (安卓和ios icon 命名唯一标识)
     * @return array
     */
    private static function _curlUploadFile($to_file_addr, $file_addr, $url, $type, $unqid = 0)
    {
        try {
            $data = array(
                'to' => $to_file_addr,
                'ip' => self::_getIp(),
                'type' => $type,
                'unqid' => $unqid,
                'file' => new CURLFile($file_addr)
            );
            $curl = curl_init();
            curl_setopt($curl, CURLOPT_URL, $url);
            curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($curl, CURLOPT_POST, true);
            curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
            $content = curl_exec($curl);
            curl_close($curl);
            return json_decode($content, true);
        } catch (\Exception $e) {
            return array();
        }
    }

有兼容也有定制, 记录一下仿 fis3 http上传文件方法格式 各种to参数 尚未加效验key 仅添加IP白名单;

参数介绍 :

to 指定存放图片的目录
ip 前端加白ip 服务端未做验证(提供给后台使用)
type 上传文件的类型
unqid 多图片上传定制同名图片使用(看代码吧)
file 上传文件的地址
最后修改:2017 年 07 月 07 日 08 : 02 PM
如果觉得我的文章对你有用,请随意赞赏

发表评论