$HTTP_RAW_POST_DATA 和 WordPress media_handle_upload
因此,我正在制作一些东西,用户需要使用 WordPress 内置的媒体上传 API 从画布元素(在前端)上传图像。
我已经使用 API 从表单中的文件输入成功上传了图像:
<input type="file" name="async-upload" id="async-upload" size="40" />
...
<?php $new_attach_id = media_handle_upload( 'async-upload', $new_id ); ?>
并且我使用自己的脚本从画布保存了图像:
<script type="text/javascript">
...
var img = canvas.toDataURL("image/png");
...
ajax.send(img );
</script>
...
<?php
$imageData=$GLOBALS['HTTP_RAW_POST_DATA'];
$filteredData=substr($imageData, strpos($imageData, ",")+1);
$unencodedData=base64_decode($filteredData);
$fp = fopen( 'saved_images/canv_save_test.png', 'wb' );
fwrite( $fp, $unencodedData);
...
?>
问题是,Wordpress 的 media_handle_upload() 只接受 $_FILES 数组的索引进行上传。
所以问题是:如何将图像数据从 HTTP_RAW_POST_DATA 传递给它?我可以让 $_FILES['tmp-name'] 以某种方式指向它吗?我可以使用另一个脚本作为中间步骤吗?我可以让猴子们敲打字机,直到它们得出答案吗?
非常感谢任何帮助!
谢谢, 凯恩
编辑:已解决
感谢@alex的file_put_contents建议,以及我发布的另一个相关问题的答案 这里 我现在可以正常工作了。解决方案:在 HTTP 请求中发送未更改的 Base64 图像数据,覆盖 PHP 生成的 tmp_file 并关闭 WP 的一些安全检查。不知道这有多安全,但对于遇到同样问题的人来说,这是代码:
<script type="text/javascript">
$('#save').click(function() {
// get image data from cavas
var img = canvas.toDataURL("image/png");
// open ajax request
var ajax = new XMLHttpRequest();
ajax.open("POST",script_url,false);
//ajax.open("POST","/dumpvars.php",false); // testing
// set headers
boundary_str = "AJAX-------------" + (new Date).getTime();
ajax.setRequestHeader('Content-Type', "multipart/form-data; boundary=" + boundary_str);
// callback for completed request
ajax.onreadystatechange=function()
{
if (ajax.readyState == 4)
{
// Write out the filename.
$("#ajax_out").html("Response: "+ajax.responseText+" End Response");
}
}
// BUILD REQUEST
var boundary = '--' + boundary_str;
var request_body = boundary + '\n'
// print all html form fields
$('#save_form input').each(function(){
request_body += 'Content-Disposition: form-data; name="'
+ $(this).attr('name') + '"' + '\n'
+ '\n'
+ $(this).val() + '\n'
+ '\n'
+ boundary + '\n';
});
// make filename
var filename = $('#save_form input[name="title"]').val();
filename = filename.replace(/\s+/g, '-').toLowerCase(); // hyphenate + lowercase
filename = encodeURIComponent(filename) + (new Date).getTime() + ".png";
// add image
request_body += 'Content-Disposition: form-data; name="async-upload"; filename="'
+ filename + '"' + '\n'
+ 'Content-Type: image/png' + '\n'
+ '\n'
+ img
+ '\n'
+ boundary;
// Send request
ajax.send(request_body);
});
</script>
...
<?php
// Get transmitted image data
$loc = $_FILES['async-upload']['tmp_name'];
$file = fopen($loc, 'rb');
$contents = fread($file, filesize($loc));
fclose($file);
// Decode image data
$filteredData=substr($contents, strpos($contents, ",")+1);
$unencodedData=base64_decode($filteredData);
// Overwrite temp file
file_put_contents($loc, $unencodedData);
// Pass image data to WP Upload (attach to post)
$override['test_upload'] = false; // Override WP's upload security test (rewriting tmp_name made it fail)
$override['test_form'] = false;
$new_attach_id = media_handle_upload( 'async-upload', $new_id, array() , $override );
?>
So I'm making something for which users need to upload images from a canvas element (on the front end) using Wordpress's in-built Media Upload API.
I've successfully uploaded images with the API from a file input in a form:
<input type="file" name="async-upload" id="async-upload" size="40" />
...
<?php $new_attach_id = media_handle_upload( 'async-upload', $new_id ); ?>
and I've saved images from the canvas using my own script:
<script type="text/javascript">
...
var img = canvas.toDataURL("image/png");
...
ajax.send(img );
</script>
...
<?php
$imageData=$GLOBALS['HTTP_RAW_POST_DATA'];
$filteredData=substr($imageData, strpos($imageData, ",")+1);
$unencodedData=base64_decode($filteredData);
$fp = fopen( 'saved_images/canv_save_test.png', 'wb' );
fwrite( $fp, $unencodedData);
...
?>
Problem is, Wordpress's media_handle_upload() only accepts an index to the $_FILES array for the upload.
So the question is: How can I pass the image data from HTTP_RAW_POST_DATA to it? Could I make the $_FILES['tmp-name'] point to it somehow? Could I use another script as an intermediate step somehow? Could I unleash the monkeys on the typewriter until they come up with the answer?
Any help very very much appreciated!
Thanks,
Kane
EDIT: Solved
Thanks to @alex for his file_put_contents suggestion, and answers to another related question I posted here I now have this working. Solution: Send the unaltered base64 image data in the HTTP request, overwrite the tmp_file PHP generates and turn some security checks off for WP. Don't know how safe that is but here's the code for anyone who has the same problem:
<script type="text/javascript">
$('#save').click(function() {
// get image data from cavas
var img = canvas.toDataURL("image/png");
// open ajax request
var ajax = new XMLHttpRequest();
ajax.open("POST",script_url,false);
//ajax.open("POST","/dumpvars.php",false); // testing
// set headers
boundary_str = "AJAX-------------" + (new Date).getTime();
ajax.setRequestHeader('Content-Type', "multipart/form-data; boundary=" + boundary_str);
// callback for completed request
ajax.onreadystatechange=function()
{
if (ajax.readyState == 4)
{
// Write out the filename.
$("#ajax_out").html("Response: "+ajax.responseText+" End Response");
}
}
// BUILD REQUEST
var boundary = '--' + boundary_str;
var request_body = boundary + '\n'
// print all html form fields
$('#save_form input').each(function(){
request_body += 'Content-Disposition: form-data; name="'
+ $(this).attr('name') + '"' + '\n'
+ '\n'
+ $(this).val() + '\n'
+ '\n'
+ boundary + '\n';
});
// make filename
var filename = $('#save_form input[name="title"]').val();
filename = filename.replace(/\s+/g, '-').toLowerCase(); // hyphenate + lowercase
filename = encodeURIComponent(filename) + (new Date).getTime() + ".png";
// add image
request_body += 'Content-Disposition: form-data; name="async-upload"; filename="'
+ filename + '"' + '\n'
+ 'Content-Type: image/png' + '\n'
+ '\n'
+ img
+ '\n'
+ boundary;
// Send request
ajax.send(request_body);
});
</script>
...
<?php
// Get transmitted image data
$loc = $_FILES['async-upload']['tmp_name'];
$file = fopen($loc, 'rb');
$contents = fread($file, filesize($loc));
fclose($file);
// Decode image data
$filteredData=substr($contents, strpos($contents, ",")+1);
$unencodedData=base64_decode($filteredData);
// Overwrite temp file
file_put_contents($loc, $unencodedData);
// Pass image data to WP Upload (attach to post)
$override['test_upload'] = false; // Override WP's upload security test (rewriting tmp_name made it fail)
$override['test_form'] = false;
$new_attach_id = media_handle_upload( 'async-upload', $new_id, array() , $override );
?>
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您可以在某处
file_put_contents()
数据,然后创建自己的假$_FILES
数组来欺骗WordPress函数。You could
file_put_contents()
the data somewhere, and then make your own faux$_FILES
array to trick the WordPress function.我将更新这篇文章,介绍我是如何做到这一点的,以防其他人在将 Canvas 数据作为帖子附件保存到 Wordpress 时遇到困难。
我没有使用必须使用 $_FILES 数组的 media_handle_upload ,而是使用了 media_sideload_image 函数。为此,您只需将画布图像保存到服务器上的文件夹中,然后将该 URL 传递给 media_sideload_image 和帖子 ID 即可。它将将该文件附加到您的帖子中,并将图像复制到您的上传文件夹中。您可以在服务器上创建一个 TEMP_UPLOADS 文件夹来存储上传的文件,然后在成功将其附加到帖子后手动将其删除。
上面的示例不会删除旧的临时文件,但您可以轻松地弄清楚如何执行此操作。我觉得这个解决方案更加简单并且效果完美。
Im going to update this post with how I went about doing this just in case somebody else is struggling with saving Canvas data to Wordpress as a post attachment.
Instead of using media_handle_upload where you have to use the $_FILES array I used the media_sideload_image function. In order to do that all you have to do is just save your canvas image to a folder on your server then pass that URL to media_sideload_image and the post ID and that is it. It will attach that file to your post and copy the image to your uploads folder. You can create a TEMP_UPLOADS folder on your server to store your uploaded file then upon success of attaching it to a post deleting it manually.
the above sample does not delete the old temp file but you can easily figure out how to do that. I feel this solution is a lot simpler and works perfectly.