<?php
/**
 * 炎酷CMS - 上传安全校验公共库
 * 被 api/upload.php 与 api/ueditor.php 复用：
 * 后缀白名单 + 多点文件名拒绝 + getimagesize 内容校验 + 随机文件名 + 日期目录 + 写 yk_upload
 */
defined('YKCMS') or exit('Access Denied');

/** 图片 MIME => 允许对应的后缀 */
function yk_up_mime_map() {
    return array(
        'image/jpeg' => array('jpg', 'jpeg'),
        'image/png'  => array('png'),
        'image/gif'  => array('gif'),
        'image/webp' => array('webp'),
        'image/vnd.microsoft.icon' => array('ico'),
        'image/x-icon' => array('ico'),
    );
}

/** 站点配置的后缀白名单 */
function yk_up_allow_exts() {
    $exts = array();
    foreach (explode(',', strtolower(site_config('upload_ext', 'jpg,jpeg,png,gif,webp'))) as $e) {
        $e = trim($e);
        if ($e !== '') $exts[] = $e;
    }
    return $exts;
}

/** 大小上限（字节），配置 upload_max 单位 MB */
function yk_up_max_bytes() {
    return max(1, (int)site_config('upload_max', '2')) * 1024 * 1024;
}

/** 可执行/脚本类后缀硬黑名单（即使在白名单中也拒绝） */
function yk_up_deny_exts() {
    return array('php', 'phtml', 'pht', 'php3', 'php4', 'php5', 'php6', 'php7', 'phar',
        'pl', 'py', 'sh', 'cgi', 'asp', 'aspx', 'jsp', 'jspx', 'htaccess', 'htpasswd',
        'exe', 'dll', 'so', 'bat', 'cmd', 'com');
}

/**
 * 校验原始文件名，返回小写后缀；失败返回 false 并填 $err。
 * 红线：文件名含多个点（evil.php.jpg）一律拒绝；命中黑名单或不在白名单拒绝。
 */
function yk_up_check_filename($origName, &$err) {
    $err  = '';
    $base = basename((string)$origName);
    if ($base === '' || strpos($base, "\0") !== false) {
        $err = '文件名无效';
        return false;
    }
    if (substr_count($base, '.') !== 1) {
        $err = '文件名不合法（多个点或无后缀）';
        return false;
    }
    $ext = strtolower(pathinfo($base, PATHINFO_EXTENSION));
    if ($ext === '') {
        $err = '缺少文件后缀';
        return false;
    }
    if (in_array($ext, yk_up_deny_exts(), true)) {
        $err = '不允许的文件类型：.' . $ext;
        return false;
    }
    if (!in_array($ext, yk_up_allow_exts(), true)) {
        $err = '不允许的文件类型：.' . $ext;
        return false;
    }
    return $ext;
}

/**
 * 校验磁盘上的文件内容确实是图片，且真实 MIME 与后缀对应。
 */
function yk_up_check_image_content($filePath, $ext, &$err) {
    $err = '';
    if (!is_file($filePath)) {
        $err = '上传文件不存在';
        return false;
    }
    $info = @getimagesize($filePath);
    if ($info === false || empty($info[0]) || (int)$info[0] <= 0) {
        $err = '文件内容不是有效图片';
        return false;
    }
    $mime = isset($info['mime']) ? $info['mime'] : '';
    foreach (yk_up_mime_map() as $m => $exts) {
        if ($m === $mime && in_array($ext, $exts, true)) {
            return true;
        }
    }
    $err = '图片内容与后缀不匹配（' . $mime . ' / .' . $ext . '）';
    return false;
}

/** 净化用于展示的原始文件名 */
function yk_up_clean_name($origName) {
    $name = basename((string)$origName);
    $name = preg_replace('/[\x00-\x1f\x7f<>"\'\\\\]+/', '', $name);
    return mb_substr($name === '' ? 'file' : $name, 0, 100);
}

/**
 * 落盘 + 写 yk_upload。
 * @param string $srcFile     源文件路径（临时文件）
 * @param string $ext         已校验后缀
 * @param string $origName    原始文件名（仅用于展示）
 * @param string $category    分类
 * @param bool   $isUploaded  true 用 move_uploaded_file，false 用 rename/copy
 * @return array|false 成功返回 array(url,name,size)，失败 false 并填 $err
 */
function yk_up_store($srcFile, $ext, $origName, $category, $isUploaded, &$err) {
    $err = '';
    $subDir  = date('Ymd');
    $saveDir = dirname(__DIR__) . '/uploads/' . $subDir;
    if (!is_dir($saveDir) && !@mkdir($saveDir, 0755, true)) {
        $err = '上传目录创建失败';
        return false;
    }
    try {
        $rand = bin2hex(random_bytes(3));
    } catch (Exception $e) {
        $rand = (string)mt_rand(100000, 999999);
    }
    $newName = date('YmdHis') . '_' . $rand . '.' . $ext;
    $dest    = $saveDir . '/' . $newName;
    if ($isUploaded) {
        $ok = @move_uploaded_file($srcFile, $dest);
    } else {
        $ok = @rename($srcFile, $dest) || @copy($srcFile, $dest);
    }
    if (!$ok) {
        $err = '文件保存失败，请检查 uploads 目录权限';
        return false;
    }
    @chmod($dest, 0644);
    $size = (int)filesize($dest);
    $url  = 'uploads/' . $subDir . '/' . $newName;
    $category = trim((string)$category);
    if ($category === '') $category = '默认';
    db_insert('INSERT INTO ' . DB_PREFIX . 'upload (filepath, filesize, category, add_time) VALUES (?, ?, ?, ?)',
        array($url, $size, mb_substr($category, 0, 50), time()));
    return array(
        'url'  => $url,
        'name' => yk_up_clean_name($origName),
        'size' => $size,
    );
}
