图片上传 Javascript PHP - 如何保留原始文件名?

Posted

技术标签:

【中文标题】图片上传 Javascript PHP - 如何保留原始文件名?【英文标题】:Image Upload Javascript PHP - How to keep original filename? 【发布时间】:2018-08-19 21:43:18 【问题描述】:

我正在尝试在我的 CMS 中为画廊构建一个 Image Uplaoder。 我做了一些研究,找到了构建它所需的东西。 上传者使用三个文件。第一个是选择要上传的图像并显示一些进度的位置。与此相关的是一个 js 文件,用于首先调整所选图像的大小,然后再上传它们。最后但并非最不重要的一个文件,用于通过 php 处理服务器上的图像并将数据写入 sql-database。

优点是:一切都按应有的方式运行。 但是我对图像进行排序有问题。因为他们正在获取一个 md5 生成的文件名,并且上传者一次处理多个图像,所以我在一天结束时拍摄的一些图像首先显示,而当天的第一张照片例如在它们之间的任何位置。

所以我的问题来了:有没有办法保留原始文件名并将上传的图像命名为例如“1234md5randomdigits_ORIGINALFILENAME.jpg”之类的名称?

我尝试了很多 $_FILES 和其他 php 参数,但它们都是空的...

这是我用于选择图像的上传文件:

<!DOCTYPE html>
    <html>
        <head>
            <title>multiple.php</title>
            <link rel="stylesheet" href="./style.css" />
        <head>
        <body>

            <h1>Upload Images...</h1>

            <form>
                <input type="file" multiple />
                <div class="photos">

                </div>
            </form>

            <script src="./upload.js"></script>
        </body>
    </html>

upload.js 文件来了

// Once files have been selected
document.querySelector('form input[type=file]').addEventListener('change', function(event)

    // Read files
    var files = event.target.files;

    // Iterate through files
    for (var i = 0; i < files.length; i++) 

        // Ensure it's an image
        if (files[i].type.match(/image.*/)) 

            // Load image
            var reader = new FileReader();
            reader.onload = function (readerEvent) 
                var image = new Image();
                image.onload = function (imageEvent) 

                    // Add elemnt to page
                    var imageElement = document.createElement('div');
                    imageElement.classList.add('uploading');
                    imageElement.innerHTML = '<span class="progress"><span></span></span>';
                    var progressElement = imageElement.querySelector('span.progress span');
                    progressElement.style.width = 0;
                    document.querySelector('form div.photos').appendChild(imageElement);

                    // Resize image
                    var canvas = document.createElement('canvas'),
                        max_size = 1200,
                        width = image.width,
                        height = image.height;
                    if (width > height) 
                        if (width > max_size) 
                            height *= max_size / width;
                            width = max_size;
                        
                     else 
                        if (height > max_size) 
                            width *= max_size / height;
                            height = max_size;
                        
                    
                    canvas.width = width;
                    canvas.height = height;
                    canvas.getContext('2d').drawImage(image, 0, 0, width, height);

                    // Upload image
                    var xhr = new XMLHttpRequest();
                    if (xhr.upload) 

                        // Update progress
                        xhr.upload.addEventListener('progress', function(event) 
                            var percent = parseInt(event.loaded / event.total * 100);
                            progressElement.style.width = percent+'%';
                        , false);

                        // File uploaded / failed
                        xhr.onreadystatechange = function(event) 
                            if (xhr.readyState == 4) 
                                if (xhr.status == 200) 

                                    imageElement.classList.remove('uploading');
                                    imageElement.classList.add('uploaded');
                                    imageElement.style.backgroundImage = 'url('+xhr.responseText+')';

                                    console.log('Image uploaded: '+xhr.responseText);

                                 else 
                                    imageElement.parentNode.removeChild(imageElement);
                                
                            
                        

                        // Start upload
                        xhr.open('post', 'process.php', true);
                        xhr.send(canvas.toDataURL('image/jpeg'));

                    

                

                image.src = readerEvent.target.result;

            
            reader.readAsDataURL(files[i]);
        

    

    // Clear files
    event.target.value = '';

);

这是我的“process.php”来处理上传的数据:

<?php
$save_path="/images";
// Generate filename
$filename = md5(mt_rand()).".jpg";

// Read RAW data
$data = file_get_contents("php://input");

// Read string as an image file
$image = file_get_contents("data://".substr($data, 5));

// Save to disk
if ( ! file_put_contents($save_path.$filename, $image)) 
    exit();


// Clean up memory
unset($data);
unset($image);

//Includes and SQL go after that

// Return file URL
echo $save_path.$filename;
?>

如果能得到帮助,我会非常高兴! :)

【问题讨论】:

您可以发送带有文件名的自定义标头(通过 ajax 函数)并在 php 中处理该标头 【参考方案1】:

这是我用来处理可能任意数量的上传文件的方法,如果您将文件名保留在此处,它将与用户文件名相同。使您的表单元素名称成为一个数组,它将通过它循环上传所有文件。您还必须将表单类型设置为多部分。不过,这应该比您尝试执行的操作更容易管理。

    $target_dir = "images/";
    extract($_POST);
    $error=array();
    $extension=array("jpg", "gif");
    $i=0;
    foreach($_FILES["filetoupload"]["tmp_name"] as $key=>$tmp_name) 
        $file_name = $_FILES["filetoupload"]["name"][$key];
        $ext = strtolower(pathinfo($file_name,PATHINFO_EXTENSION));
        $file_tmp=$_FILES["filetoupload"]["tmp_name"][$key];
        if(in_array($ext,$extension))   
            if ($_FILES["filetoupload"]["size"][$key] < 5000000) 
                if ($_FILES["filetoupload"]["size"][$key] != 0) 
                    if(!file_exists( $target_dir . $file_name ))  
                        move_uploaded_file($file_tmp , $target_dir . $file_name );
                    
                
            
         else 
            array_push($error,"$file_name, ");
        
    

在本例中,所有文件输入字段的名称属性为 name="filetoupload[]"

【讨论】:

感谢您的建议!欣赏它!但我想先通过javascript处理和调整图像大小,这样上传不会花费太长时间,并且可以为服务器节省一些工作。 这将是相同的解决方案,您只是通过表单或 ajax 发送帖子数据。【参考方案2】:

为了支持我上面的评论,如果您在 ajax 函数中发送自定义标头,您可以处理该服务器端。我想我的语法正确,可以从 files 集合中访问文件名

/* ajax: add custom header */
xhr.open('post', 'process.php', true);
xhr.setRequestHeader( 'filename', files[i].name );
xhr.send(canvas.toDataURL('image/jpeg'));


/* php: resort to original md5 name if header failed  */
$filename=!empty( $_SERVER['HTTP_FILENAME'] ) ? $_SERVER['HTTP_FILENAME'] : md5(mt_rand()).".jpg";

由于我最初忘记将 HTTP_ 添加到自定义标头 ( php ) 的开头,它最初不会起作用 - 代表我的一个简单的疏忽。为了纠正这一点,我整理了一个从头到尾使用自定义标题想法的快速演示,尽管下面的代码并没有完全模拟您的原始代码与图像处理、画布、FileReader 等,它确实显示了分配的重要方面自定义请求标头以及如何在 php 中处理该服务器端,所以我希望它能让您了解如何实现原始文件名功能。

<?php
    /* 
        emulate server side processing of uploaded file - 
        here it simply sends back the custom headers and
        a single POST variable but this would be processing
        the image data and saving the file  
    */
    if( $_SERVER['REQUEST_METHOD']=='POST' )
        ob_clean();

        $filename = !empty( $_SERVER['HTTP_FILENAME'] ) ? $_SERVER['HTTP_FILENAME'] : md5( mt_rand() ).".jpg";
        $filetype = !empty( $_SERVER['HTTP_FILETYPE'] ) ? $_SERVER['HTTP_FILETYPE'] : 'M.I.A';
        $filesize = !empty( $_SERVER['HTTP_FILESIZE'] ) ? $_SERVER['HTTP_FILESIZE'] : 'M.I.A';

        $action   = !empty( $_POST['action'] ) ? $_POST['action'] : 'M.I.A';

        /* send proper content type response header */
        header( 'Content-Type: application/json' );

        /* add some custom response headers to show how you can pass headers and process them */
        header( sprintf( 'Uploaded-Filename: %s', $filename ) );
        header( sprintf( 'Uploaded-Filesize: %s', $filesize ) );
        header( sprintf( 'Uploaded-Filetype: %s', $filetype ) );

        /* send payload back to ajax callback */
        exit( json_encode( array(
            'filename'  =>  $filename,
            'filesize'  =>  $filesize,
            'filetype'  =>  $filetype,
            'action'    =>  $action
        )));
    
?>
<!doctype html>
<html>
    <head>
        <title>ajax custom headers</title>
        <style>
            body,body *
                font-family:calibri,verdana,arial;
                font-size:0.9rem;
            
        </style>
        <script>
            function bindEvents()
                /* DOM elements */
                var oDiv=document.getElementById('results');
                var oPre=document.getElementById('headers');
                var oBttn=document.getElementById('bttn');
                var oFile=document.querySelector('form input[type="file"]');


                /* basic callback function to show response */
                var callback=function(r,h)
                    oDiv.innerHTML=r;
                    oPre.innerHTML=h;
                

                oBttn.onclick=function()
                    /* as there is only a single file we know the index is zero */
                    var oCol=oFile.files;
                    var file=oCol.item(0).name;
                    var size=oCol.item(0).size;
                    var type=oCol.item(0).type;


                    /* ultra basic ajax request with custom request headers */
                    var xhr=new XMLHttpRequest();
                    xhr.onreadystatechange=function()
                        if( this.readyState==4 && this.status==200 )
                            /*
                                The callback can take whatever arguments we want - here simply
                                the response and some headers - could easily process specific
                                response headers rather than all
                            */
                            callback.call( this, this.response, this.getAllResponseHeaders() );
                        
                    ;
                    xhr.open( 'POST', location.href, true );
                    xhr.setRequestHeader( 'Content-Type', 'application/x-www-form-urlencoded' );
                    /* add custom request headers - original file details */
                    xhr.setRequestHeader( 'filename', file );
                    xhr.setRequestHeader( 'filetype', type );
                    xhr.setRequestHeader( 'filesize', size );

                    xhr.send( 'action=headers-test' );                  
                
            

            document.addEventListener( 'DOMContentLoaded', bindEvents, false );
        </script>
    </head>
    <body>
        <div id='results'></div>
        <pre id='headers'></pre>
        <form method='post'>
            <input type='file' />
            <input type='button' id='bttn' value='Send Ajax Request with custom headers' />
        </form>
    </body>
</html>

根据您对多个同名文件的评论,希望以下内容可能有所帮助。

<form method='post'>
    <input type='file' multiple=true />
    <input type='button' id='bttn' value='Send Ajax Request with custom headers' />
    <div class='photos'></div>
</form>


<script>

    document.querySelector( 'form input[type="file"]' ).addEventListener( 'change', function( event )

        // Read files
        var files = event.target.files;

        // Iterate through files
        for( var i = 0; i < files.length; i++ ) 

            // Ensure it's an image
            if ( files[i].type.match( /image.*/ ) ) 


                // Load image
                var reader = new FileReader();
                    /* 
                        assign custom properties to the reader 
                        object which will allow you to access 
                        them within callbacks 
                    */
                    reader.filename=files[i].name;
                    reader.filesize=files[i].size;
                    reader.filetype=files[i].type;

                reader.onload = function( readerEvent ) 


                    /*
                        assign each new image with the properties from the reader
                        - these will be available within the ajax function so you
                        can set the custom headers
                    */
                    var image = new Image();
                        image.filename=this.filename;
                        image.filesize=this.filesize;
                        image.filetype=this.filetype;

                    image.onload = function( imageEvent ) 

                        console.log('image onload - - - > > > > > %s -> %s',this.filename,this.filesize);


                        // Add element to page
                        var imageElement = document.createElement('div');
                            imageElement.classList.add('uploading');
                            imageElement.innerHTML = '<span class="progress"><span></span></span>';

                        var progressElement = imageElement.querySelector('span.progress span');
                            progressElement.style.width = 0;

                        document.querySelector('form div.photos').appendChild( imageElement );

                        // Resize image
                        var canvas = document.createElement('canvas'),
                            max_size = 1200,
                            width = image.width,
                            height = image.height;
                        if ( width > height ) 
                            if( width > max_size ) 
                                height *= max_size / width;
                                width = max_size;
                            
                         else 
                            if( height > max_size ) 
                                width *= max_size / height;
                                height = max_size;
                            
                        
                        canvas.width = width;
                        canvas.height = height;
                        canvas.getContext('2d').drawImage( image, 0, 0, width, height );

                        // Upload image
                        var xhr = new XMLHttpRequest();
                        if( xhr.upload ) 


                            xhr.upload.addEventListener('progress', function(event) 
                                var percent = parseInt( event.loaded / event.total * 100 );
                                progressElement.style.width = percent+'%';
                            , false);


                            xhr.onreadystatechange = function(event) 
                                if( xhr.readyState == 4 ) 
                                    if( xhr.status == 200 ) 

                                        imageElement.classList.remove('uploading');
                                        imageElement.classList.add('uploaded');
                                        imageElement.style.backgroundImage = 'url('+xhr.responseText+')';

                                     else 
                                        imageElement.parentNode.removeChild( imageElement );
                                    
                                
                            
                            xhr.open( 'post', location.href, true ); //'process.php'
                            xhr.setRequestHeader( 'filename', image.filename );
                            xhr.setRequestHeader( 'filetype', image.filetype );
                            xhr.setRequestHeader( 'filesize', image.filesize );
                            xhr.send( canvas.toDataURL('image/jpeg') );
                        
                    ;
                    image.src = readerEvent.target.result;
                ;
                reader.readAsDataURL( files[i] );
            
        
        // Clear files
        event.target.value = '';
    );
</script>

【讨论】:

感谢您的快速帮助!真的很感激!我使用了自定义标题的想法,它工作得非常好 - 谢谢!但不幸的是,现在还有另一个问题。只要只上传一张图片,一切都会很好。通过上传多张图片,接下来的每张图片都会像第一个一样命名。上传图片后有没有办法取消设置或清除自定义标题? ajax 请求应该与每个文件一起发送一个自定义标头,因此oCol.item(0).name 中使用的索引需要是一个变量 - 在您的代码中,您使用了i,所以它将是files[i].name 我的 for 循环一定有问题,但我不明白。即使我使用i 代替文件名,我得到的只是上传的图像总数。如果只上传一张图片,我会使用i 得到正确的数字 1。但如果我要上传 f.e. 10 张图片,i 在我用我的 process.php 写入数据库的每个字符串中都有值 10,即使保存了正确的图像并且所有图像都不同......怎么了? 当然,给你... process.php - upload.js 文件选择的 html 与我上面的帖子一样没有变化。因为我想获取图像编号,所以我已将 FILENAME 更改为 FILENUM。感谢您的努力! 查看更新以回答上面的问题-在测试中对我有用-也许可以简化

以上是关于图片上传 Javascript PHP - 如何保留原始文件名?的主要内容,如果未能解决你的问题,请参考以下文章

php中上传多张图片,如何解决?

如何将过滤器应用于照片并将其保存到数据库 php css javascript

小程序真机调试图片可以成功上传,但是线上版本和体验版手机上上传老保图片报错?

ckeditor 上传图片 php版

keditor_php图片上传

PHP上传图片