阻止某些文件被上传

时间:2016-11-13 13:34:38

标签: php

我需要阻止php,pl,cgi上传到我的网站。这怎么可能?我尝试了很多奇怪的事情而且我没有希望,我从来没有让它发挥作用。

所以是的,需要阻止php,pl和cgi。

代码:

<?php
session_start();

/**
 * Handles POST uploads, generates filenames, moves files around and commits
 * uploaded metadata to database.
 */

require_once 'classes/Response.class.php';
require_once 'classes/UploadException.class.php';
require_once 'classes/UploadedFile.class.php';
require_once 'includes/database.inc.php';

/**
 * Generates a random name for the file, retrying until we get an unused one.
 *
 * @param UploadedFile $file
 *
 * @return string
 */
function generateName($file)
{
    global $db;
    global $doubledots;

    // We start at N retries, and --N until we give up
    $tries = POMF_FILES_RETRIES;
    $length = POMF_FILES_LENGTH;
    $ext = pathinfo($file->name, PATHINFO_EXTENSION);

    // Check if extension is a double-dot extension and, if true, override $ext
    $revname = strrev($file->name);
    foreach ($doubledots as $ddot) {
        if (stripos($revname, $ddot) === 0) {
            $ext = strrev($ddot);
        }
    }

    do {
        // Iterate until we reach the maximum number of retries
        if ($tries-- === 0) {
            throw new Exception(
                'Gave up trying to find an unused name',
                500
            ); // HTTP status code "500 Internal Server Error"
        }

        $chars = ID_CHARSET;
        $name = '';
        for ($i = 0; $i < $length; ++$i) {
            $name .= $chars[mt_rand(0, strlen($chars))];
        }

        // Add the extension to the file name
        if (isset($ext) && $ext !== '') {
            $name .= '.'.$ext;
        }

        // Check if a file with the same name does already exist in the database
        $q = $db->prepare('SELECT COUNT(filename) FROM files WHERE filename = (:name)');
        $q->bindValue(':name', $name, PDO::PARAM_STR);
        $q->execute();
        $result = $q->fetchColumn();
    // If it does, generate a new name
    } while ($result > 0);

    return $name;
}

/**
 * Handles the uploading and db entry for a file.
 *
 * @param UploadedFile $file
 *
 * @return array
 */
function uploadFile($file)
{
    global $db;
    global $FILTER_MODE;
    global $FILTER_MIME;

    // Handle file errors
    if ($file->error) {
        throw new UploadException($file->error);
    }

    // Check if mime type is blocked
    if (!empty($FILTER_MIME)) {
        if ($FILTER_MODE == true) { //whitelist mode
            if (!in_array($file->mime, $FILTER_MIME)) {
                throw new UploadException(UPLOAD_ERR_EXTENSION);
            }
        } else { //blacklist mode
            if (in_array($file->mime, $FILTER_MIME)) {
                throw new UploadException(UPLOAD_ERR_EXTENSION);
            }
        }
    }


    // Check if a file with the same hash and size (a file which is the same)
    // does already exist in the database; if it does, return the proper link
    // and data. PHP deletes the temporary file just uploaded automatically.
    $q = $db->prepare('SELECT filename, COUNT(*) AS count FROM files WHERE hash = (:hash) '.
                      'AND size = (:size)');
    $q->bindValue(':hash', $file->getSha1(), PDO::PARAM_STR);
    $q->bindValue(':size', $file->size, PDO::PARAM_INT);
    $q->execute();
    $result = $q->fetch();
    if ($result['count'] > 0) {
        return array(
            'hash' => $file->getSha1(),
            'name' => $file->name,
            'url' => POMF_URL.rawurlencode($result['filename']),
            'size' => $file->size,
        );
    }

    // Generate a name for the file
    $newname = generateName($file);

    // Store the file's full file path in memory
    $uploadFile = POMF_FILES_ROOT . $newname;

    // Attempt to move it to the static directory
    if (!move_uploaded_file($file->tempfile, $uploadFile)) {
        throw new Exception(
            'Failed to move file to destination',
            500
        ); // HTTP status code "500 Internal Server Error"
    }

    // Need to change permissions for the new file to make it world readable
    if (!chmod($uploadFile, 0644)) {
        throw new Exception(
            'Failed to change file permissions',
            500
        ); // HTTP status code "500 Internal Server Error"
    }

    // Add it to the database
    if (empty($_SESSION['id'])) {
        // Query if user is NOT logged in
        $q = $db->prepare('INSERT INTO files (hash, originalname, filename, size, date, ' .
                    'expire, delid) VALUES (:hash, :orig, :name, :size, :date, ' .
                        ':exp, :del)');
    } else {
        // Query if user is logged in (insert user id together with other data)
        $q = $db->prepare('INSERT INTO files (hash, originalname, filename, size, date, ' .
                    'expire, delid, user) VALUES (:hash, :orig, :name, :size, :date, ' .
                        ':exp, :del, :user)');
        $q->bindValue(':user', $_SESSION['id'], PDO::PARAM_INT);
    }

    // Common parameters binding
    $q->bindValue(':hash', $file->getSha1(), PDO::PARAM_STR);
    $q->bindValue(':orig', strip_tags($file->name), PDO::PARAM_STR);
    $q->bindValue(':name', $newname, PDO::PARAM_STR);
    $q->bindValue(':size', $file->size, PDO::PARAM_INT);
    $q->bindValue(':date', date('Y-m-d'), PDO::PARAM_STR);
    $q->bindValue(':exp', null, PDO::PARAM_STR);
    $q->bindValue(':del', sha1($file->tempfile), PDO::PARAM_STR);
    $q->execute();

    return array(
        'hash' => $file->getSha1(),
        'name' => $file->name,
        'url' => POMF_URL.rawurlencode($newname),
        'size' => $file->size,
    );
}

/**
 * Reorder files array by file.
 *
 * @param  $_FILES
 *
 * @return array
 */
function diverseArray($files)
{
    $result = array();

    foreach ($files as $key1 => $value1) {
        foreach ($value1 as $key2 => $value2) {
            $result[$key2][$key1] = $value2;
        }
    }

    return $result;
}

/**
 * Reorganize the $_FILES array into something saner.
 *
 * @param  $_FILES
 *
 * @return array
 */
function refiles($files)
{
    $result = array();
    $files = diverseArray($files);

    foreach ($files as $file) {
        $f = new UploadedFile();
        $f->name = $file['name'];
        $f->mime = $file['type'];
        $f->size = $file['size'];
        $f->tempfile = $file['tmp_name'];
        $f->error = $file['error'];
        //$f->expire   = $file['expire'];
        $result[] = $f;
    }

    return $result;
}

$type = isset($_GET['output']) ? $_GET['output'] : 'json';
$response = new Response($type);

if (isset($_FILES['files'])) {
    $uploads = refiles($_FILES['files']);


    try {
        foreach ($uploads as $upload) {
            $res[] = uploadFile($upload);
        }
        $response->send($res);
    } catch (Exception $e) {
        $response->error($e->getCode(), $e->getMessage());
    }
} else {
    $response->error(400, 'No input file(s)');
}

如何?

2 个答案:

答案 0 :(得分:2)

PHP在实际上传到服务器之前无法控制文件。您的Web服务器将处理文件上载,然后授予访问php文件的权限以执行任何操作。你可以用php做的就是检查mime类型/文件扩展名来检查上传的文件是否有效,如果不是我们需要的有效文件则删除。

答案 1 :(得分:0)

您应该真正看一下PHP小组提供的有关文件上传的documentation

您还需要记住的一件事是,上传时提供的mime类型是由客户端浏览器设置的,并且基于文件扩展名;即.txt = ascii / txt,或.jpg = image / jpg。

非常容易欺骗mime类型,因此请使用fileinfo class of functions进行必要的预先准备,以便在上传后更准确地确定文件类型。