图片上传 Javascript PHP - 如何保留原始文件名?
Image Upload Javascript PHP - How to keep original filename?
我正在尝试在我的 CMS 中为画廊内置一个图像上传器。
我做了一些研究,找到了构建它所需要的东西。
上传者使用三个文件。第一个是 select 上传图片并显示一些进度的位置。连接到此的是一个 js 文件,用于先调整 selected 图像的大小,然后再上传它们。最后但并非最不重要的一个文件,用于通过 php 处理服务器上的图像并将数据写入 sql-database.
优点是:一切正常。
但是我对图像排序有问题。因为他们正在获取 md5 生成的文件名,并且上传者一次处理多张图片,所以我在一天结束时拍摄的一些图片首先显示,而当天的第一张图片则位于它们之间的任何位置。
所以我的问题来了:有没有办法保留原始文件名并为上传的图片命名,例如“1234md5randomdigits_ORIGINALFILENAME.jpg”?
我尝试了很多 $_FILES 和其他 php 参数,但它们都是空的...
这是我上传的 select 图片文件:
<!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;
?>
我很乐意提供一些帮助! :)
这就是我用来处理可能任意数量的上传文件的方法,如果您将文件名保留在此处,它将与用户文件名保持一致。将您的表单元素名称设为一个数组,它将遍历它并上传所有文件。您还必须将表单类型设置为多部分。不过,这应该比您尝试做的事情更容易管理。
$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, ");
}
}
在此示例中,所有文件输入字段的名称属性都是名称="filetoupload[]"
为了支持我上面的评论,如果您在 ajax 函数中发送自定义 header,您可以处理该服务器端。我想我的语法正确,可以从 files
collection
访问文件名
/* 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_
添加到自定义 header ( php ) 的开头,所以它最初不会起作用 - 这是我的一个简单疏忽。为了纠正这个问题,我整理了一个从头到尾使用自定义 header 想法的快速演示,尽管后面的代码并没有完全模拟您的原始代码以及图像处理、canvas、FileReader 等它确实显示了分配自定义请求 header 以及如何在 php 中处理 server-side 的重要方面,因此我希望它能让您了解如何实现原始文件名功能。
<?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>
我正在尝试在我的 CMS 中为画廊内置一个图像上传器。 我做了一些研究,找到了构建它所需要的东西。 上传者使用三个文件。第一个是 select 上传图片并显示一些进度的位置。连接到此的是一个 js 文件,用于先调整 selected 图像的大小,然后再上传它们。最后但并非最不重要的一个文件,用于通过 php 处理服务器上的图像并将数据写入 sql-database.
优点是:一切正常。 但是我对图像排序有问题。因为他们正在获取 md5 生成的文件名,并且上传者一次处理多张图片,所以我在一天结束时拍摄的一些图片首先显示,而当天的第一张图片则位于它们之间的任何位置。
所以我的问题来了:有没有办法保留原始文件名并为上传的图片命名,例如“1234md5randomdigits_ORIGINALFILENAME.jpg”?
我尝试了很多 $_FILES 和其他 php 参数,但它们都是空的...
这是我上传的 select 图片文件:
<!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;
?>
我很乐意提供一些帮助! :)
这就是我用来处理可能任意数量的上传文件的方法,如果您将文件名保留在此处,它将与用户文件名保持一致。将您的表单元素名称设为一个数组,它将遍历它并上传所有文件。您还必须将表单类型设置为多部分。不过,这应该比您尝试做的事情更容易管理。
$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, ");
}
}
在此示例中,所有文件输入字段的名称属性都是名称="filetoupload[]"
为了支持我上面的评论,如果您在 ajax 函数中发送自定义 header,您可以处理该服务器端。我想我的语法正确,可以从 files
collection
/* 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_
添加到自定义 header ( php ) 的开头,所以它最初不会起作用 - 这是我的一个简单疏忽。为了纠正这个问题,我整理了一个从头到尾使用自定义 header 想法的快速演示,尽管后面的代码并没有完全模拟您的原始代码以及图像处理、canvas、FileReader 等它确实显示了分配自定义请求 header 以及如何在 php 中处理 server-side 的重要方面,因此我希望它能让您了解如何实现原始文件名功能。
<?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>