<?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 上传文件的地址