Preview and posting images from front-end with WordPress security concerns - php

I've a front-end form with a file input where anybody (no registered users) can upload an image that will be attached to a custom meta field in the back-end. To preview the image I'm using the old iframe technique. My form looks like this:
<form id="upload-photo" method="post" target="preview-iframe" action="<?= get_template_directory_uri() ?>/inc/upload.php" enctype="multipart/form-data" >
<div id="preview"><img src="" alt="" /></div>
<iframe id="preview-iframe" name="preview-iframe" src=""></iframe>
<input type="file" name="author_photo" />
<input type="hidden" id="attachment" name="attachment" value=""/>
<button type="submit" id="upload">Upload</button>
</form>
Then I use WordPress built-in functions to handle the upload and move the file into the media gallery. I use the hidden field to store the WordPress id of the attachment so if users decide to change the picture by uploading a new one then the old one would get removed. This is my PHP:
<?php
define('WP_USE_THEMES', false);
require_once '../../../../wp-load.php';
require_once(ABSPATH .'wp-admin/includes/image.php');
require_once(ABSPATH .'wp-admin/includes/file.php');
require_once(ABSPATH .'wp-admin/includes/media.php');
if (isset($_POST['attachment'])) {
wp_delete_attachment($_POST['attachment'], true);
}
foreach ($_FILES as $file => $data) {
if ($data['error'] === UPLOAD_ERR_OK) {
$attachment = media_handle_upload($file, null);
}
}
echo wp_get_attachment_image($attachment, 'author', 0, array('id' => $attachment));
?>
And finally the jQuery that glues it all together:
var $preview = $('#preview'),
$iframe = $('#preview-iframe'),
$attachment = $('#attachment');
$('#upload').click(function() {
$iframe.load(function() {
var img = $iframe.contents().find('img')[0];
$preview.find('img').attr('src', img.src);
$attachment.val(img.id);
});
});
Everything works perfect but there are few issues with this simple approach:
If JavaScript is disabled images don't get removed
If the user uploads a file then refreshes the site and then uploads and other image, then the previous one wouldn't get deleted because the previous attachment ID doesn't exist due to the refresh.
A malicious user could edit the hidden attachment field with a different ID.
I though about uploading the files to a /temp folder for previewing purposes only and then run a cron job every X time to empty it out. But how do I then make use of WordPress functions to move the image from /temp to the gallery once the whole form has been submitted so I can get and attachment id to link to the post?
Notice that I've two forms, one for handling the image, and the global form with all the content that will be posted and that already works since I can post the new post as "draft" and admins have the power to decide. But how to do this for images securely? How to preview an image and put it in the gallery only if the form has been posted successfully?
I know about the FileReader API but I need compatibility for IE8+ so that won't do. I'm also aware of all the Flash and Silverlight solutions but that's not an option either. Also please don't just link to WordPress plugins, I'm trying to learn here.

Ok, it seems I'm answering my own questions again. This is how I solved it. I found a WordPress function media_handle_sideload that lets you upload files from other locations and not only files from the $_FILES array like the previous function.
So I went with my initial approach now that I know about that function. I basically upload the file to a /temp folder for preview purposes and give it a unique id that I store into the hidden field. When the user submits the overall form and passes validation I take the ID that was stored and find out if the file exists and if so I move it to the gallery. This solves most of my concerns about security because even if a malicious user finds an existing unique ID (unlikely but possible) the file wouldn't get removed like before, but just moved into the gallery (not a big deal).
Finally I set-up a cron job to empty out the temp folder every X amount of time.

Related

Using a form to add a hyperlink to an image before it's upload to a webpage

Please help. Is there any way to add a hyperlink to an image using a form before it's uploaded to a webpage? I would like to use a form to add links to my images so I don't have to add links to them manually because it would get time consuming. I also want to display a text caption link under the image. The image and the text caption will link to the same place. I want to use a form to add a link to an image and add a text link under the image before it's uploaded. I am using php to write the code.Thank you for your time.
This is photo of form before image is uploaded: upload form image
This is the uploaded image with text caption link under it:The upload image with link under it
This is the code:
<html>
<head>
<title>Upload and display images with PHP</title>
</head>
<?php
if(isset($_POST['upload_img'])) {
$file_name = $_FILES['image'] ['name'];
$file_type = $_FILES['image'] ['type'];
$file_size = $_FILES['image'] ['size'];
$file_tmp_name = $_FILES['image'] ['tmp_name'];
if($file_name) {
move_uploaded_file($file_tmp_name,"img/$file_name");
}
}
?>
<body>
<form action="" method="post" enctype="multipart/form-data">
<label>upload Image</label><br><br>
<input type="file" name="image"><br><br>
<label>Add hyperlink to image:</label><br>
<input type="text" name="add_link"><br><br>
<input type="submit" value="Uplad Image" name="upload_img">
</form>
<?php
$folder = "img/";
//$dir = "img/";
if(is_dir($folder)) {
if($handle = opendir($folder)) {
while(($file=readdir($handle)) != false) {
if($file ==='.' || $file ==='..') continue;
echo '<img src="img/'.$file.'" width="150" height="150" alt="">';
}
closedir($handle);
}
}
?>
</body>
</html>
Please note that users can do bad things just by choosing "appropriate" names for their files. For instance, what would happen if I named my file subfolder/something.jpg"? Or what if I called it "/><script>alert('hi');</script>? And sure, the OS may not allow complicated file names, but you can't think like that in security. Instead, remember that the client can send "any" (not any, but in this context it's the same as any) HTTP data they want to the web server; they don't even have to open that form of yours. There are a few ways of making it more secure (you can google to learn about it), but I won't go in on that now, since you asked about something else.
Moving on to your question, there are several approaches to this. What you need, is to store the link, the text and some reference to the related image somewhere. An approach which I wouldn't recommend is to store these pieces of information in a file, and then use functions like file_get_contents and file_put_contents to write/read it (for instance, you can dedicate each line in the file to a specific image, and use a seperator to seperate the different informations). The problem with this is that it's hard to make secure, and not to mention, the reading of the file will be highly inefficient when it contains a large number of data. There are more problems that I won't go into detail with (simultaneous usage, etc.), but short version is, there are better ways!
Another method is using a database. They are generally designed for this type of usage, making them efficient, safe (when configured and used correctly, that is), etc. The text/link part will go perfectly in a database, for this very reason. There are ways to store images in databases as well, although I wouldn't recommend that, since there are issues with it being slower. If you prefer, you can keep your current method, and simply create a database table with the fields:
image_name | image_link | image_text
In that case, keep the name of the image unique, as it will work as an identifier. If you use this method, all you need to do is to read the image with the given name, then search for the row in the database table WHERE image_name = *name of your image* and use the other columns of that row to print out the text/link.
The printing is done as follows:
echo '<img src="img/'.htmlspecialchars($file).'" width="150" height="150" alt="">'
echo '<br />\n';
echo ''.htmlspecialchars($text).'';
The reason why I included htmlspecialchars in the above example is to protect against XSS attacks. I won't write the code required to do the querying, because you can easily figure that out yourself just by googling for a database tutorial, if you don't already know about it. Also be sure to use prepared statements, in order to protect your website against SQL-injection.

Get and use the user's previous form data variable across the page

The purpose is to allow user uploading files (usual uploading process) and confirm uploading by pressing on the confirmation button. Programming side: 2 folders - 1 for unconfirmed files where files get deleted periodically and 2 - confirmed folder - where files are copied from unconfirmed folder if a user presses the confirmation button.
Basically, I have a form, where a user uploads files that are stored in the folder and the path to it - in a database. And on the same page I have another button, so when the user presses it I would like to move his/her uploaded files from one directory to another (not re-uploading - coping on server).The issue is taht I should know WHICH files to deal with!
My problem is: everything seems ok, but I can't get the variable $name - that tells me the name of the file, user has uploaded. Because When I try to use it to proceed second submit button - it says variable is undefined. I need to get the variable that tells me the name of the file user has submitted so I can copy that file to another directory, but it can only be assigned (and unfornunatelly used) when procesing the form submittinf and enabled to use only inside of the processing, while I want to use it outside.
I have tried to use sessions - but this code doesnt work, same problem - it says that - 'undefined index - regex', same with COOKIES.
All the html:
<form action="videator.php"method="post" enctype="multipart/form-data">
<input class="form" type="file" name="fileToUpload" id="fileToUpload" accept="video/*" >
<input class="form" type="submit" value="Upload Image" name="submit">
</form>
<form action="love.php" method="post">
<input class="post" type="submit" value="POST" name="post" id="post"/>
</form>
videator.php:
if(isset($_POST["submit"])) {
$file = $_FILES['fileToUpload'];
$name = $file['name'];
$_COOKIE['name'] = $name;
$_SESSION['regex'] = $name;
...
}
love.php
if(isset($_POST["post"])) {
session_start();
$name = $_GET['regex'];
$from = "temp_videos/".$name;
$to = "videos/";
if (!copy($from, $to)) {
echo("<script>alert('fail')</script>");
}else {
echo("<script>alert('Success!')</script>");
}
It says also that 'The first argument to copy() function can not be a directory. I guess, that's due to the fact that my variable $name is undefined, therefore only the folder is here as the path.
Please, help. I've spent all my day on that.
(If I just use copy() function with indicating actual path and not a variable of it - everything works)
Thanx in advance.
I have a few tips that may help.
(1) At the top of each PHP file, as the first instruction, put:
<?php
if (!session_id()) session_start();
//any other PHP instructions follow.
?>
(2) Try using the excellent jQuery File Upload plugin by Ravi Kusuma. Although I generally try to code everything myself and not use plugins, this one is so well done that it's my primary goto for file uploads.
(3) Until you get this working, there is no need to put the session_start() inside an if statement. The session_start() must be the first instruction at top of each PHP page that references the $_SESSION variable.
(4) Look into AJAX instead of using <form> (for managing the file upload process). Kusuma's plugin also works great with AJAX. If you haven't used AJAX before, it may sound intimidating - but it's super simple. Copy the examples at the bottom of this post and make them work on your system. It may be the most important 15 mins you've spent in 2016. Note that the point of the linked question is that there must be a separate PHP file that receives the AJAX post.
(5) Don't forget that AJAX is a two-step process: (a) the javascript on the current page communicates with the specified PHP page; (b) the PHP page receives the data (or file upload data) via POST varibles. Therefore, be sure to check out the "SERVER SIDE" tab at top of Kusuma's Hayageek page. At the top of the SERVER SIDE page are four links to sample PHP files. Study the upload.php example.
Happy coding.

jQuery View Uploaded File

I am trying to upload a file a view the file on an iFrame but it is not working.
Here is what I have tried
jQuery('.file_upload1').change(function(){ jQuery('iframe').attr('src', jQuery(this).val()); $('iframe').attr('src', $('iframe').attr('src')); });
<label><input class="file_upload1" name="file_cover" type="file"></label>
<div>
<iframe src=""></iframe>
</div>
If this does not work, can I move the uploaded file to server directory so that the path becomes valid? How would I do this?
Apart from other problems and limitations of such solution, and specifically answering "why it does not work?" question:
The change event needs to be nested in ready function:
jQuery("document").ready(function() {
jQuery('.file_upload1').change(function() {
jQuery('iframe').attr('src', jQuery(this).val());
});
});
The src attribute of iframe must be a valid non-empty URL potentially surrounded by spaces. When selecting a file with input type file, in Windows the value will be something like c:\fakepath\file name goes.here, so before using as iframe source, you will have to rework it a little bit.
Regarding
I'm trying upload file and display it on iframe forcing it to reload
You don't need to force reload to achieve this. "Upload" means the page will be reloaded (well, unless upload is handled using AJAX, but it's not the case here I guess). In order to upload a file, the form must be submitted and the page needs to be reloaded. Once reloaded, you can easily construct the full path of the file and use it in iframe, something like:
<iframe src="<?php echo $file_full_url; ?>"></iframe>
But if you want to preview the file in iframe before uploading to server - it won't be possible due to security reasons. See this question for reference: How to get full path of selected file on change of <input type=‘file’> using javascript, jquery-ajax?

PHP display chosen image before upload

I'm using Codeigniter's upload library to upload images for user avatars. I'm also using Jcrop which allows users to select an area to crop.
(source: webresourcesource.com)
I'm saving all the coordinates of the selected area in text inputs which I'll use in php to crop.
Is it possible to display the image selected before uploading?
Upload form:
<?php echo form_open_multipart('upload/do_upload');?>
<input type="file" name="userfile" size="20" />
<input type="submit" value="upload" />
</form>
If possible I'm trying to avoid heavy js for this or uploading 2 times. When choosing a file I notice that it shows the name of it:
Is there a way to use that functionality to retrieve the image path as well (path to the image in the uploader's computer)? In theory I'll be able to use that in image tags and display the image without js.
To be clear, you are not uploading the file twice in your current solution, right? You should only be uploading once, storing it in a temporary location, displaying it on the crop page, and then sending the crop parameters back on the second action.
Traditionally, there has been no way to access the contents of a file or the value of the file upload form. There would be a security risk letting a web page know the structure of your file system. (Are you on Windows, on an admin account, ...?) Eons ago you could do this, but we got wise.
The File API introduced in HTML5 makes it possible to access files without revealing this information, and there are some cool options available to your client-side application, the key ones being the files property of a file input and URL.createObjectURL.
When you change a form, an internal representation of the file(s) in the input are exposed using fileInput.files which is a FileList object. API's exist where you can read the bytes but you want to set it as the source of an image.
Since a file is not a URL, URL.createObjectURL creates a virtual URL around the file that can only be used by your page and same-origin iframes. Set the image to this, then onload, revoke the URL and kick off your jQuery cropping plugin:
input.addEventListener('change', function () {
preview.src = URL.createObjectURL(this.files[0]);
});
preview.addEventListener('load', function () {
URL.revokeObjectURL(this.src);
alert('jQuery code here. Src: ' + this.src + ', W: ' + this.width + ', H: ' + this.height);
});
Try out this jsFiddle in at least Chrome and Firefox. This is obviously not a solution for all browsers but it is a great way to enhance it for browsers that do support it.
You could potentially do it using css (http://www.seifi.org/css/creating-thumbnails-using-the-css-clip-property.html), but it's going to be incredibly hard to integrate with jcrop...
I would recommend just making the user wait until it has been uploaded. That's what facebook and most other websites that allow cropping do.
In any case it wouldn't speed up the upload process so there isn't that much a reason to do it.
You can't get the full filepath. It would be a security issue: http://forums.asp.net/t/1077850.aspx/1
Well, you can use other cropper library wich comes with a preview like the one defusion has.
http://www.defusion.org.uk/code/javascript-image-cropper-ui-using-prototype-scriptaculous/

How to upload and read text/csv file without submitting?

I have this form and I would like to read the uploaded file and then fill out the form using this read information without refreshing the page.
For example the first word might be "Bob" and so I would want that to go in my input text "First_name." I've been trying to searching online for a way to do this using JQuery or Ajax but I can't seem to find a solution.
Can this be done using the two methods previously mentioned? If so and if not can someone point me to a link or to where I can learn how to do this? The instances I have found include where one uses JQuery to upload the file and display the size without refresh (which is not exactly what I want).
I have also found how one can use an iFrame but this again is not what I want. I suppose I could always just submit the part of the page containing the textfile related information and show the same form but with the filled out information. But I feel as if this is kind of sloppy and I want to know if there is a better way.
Thanks.
Firefox has a method to do this, the File and FileList API provide a way to get at the files selected by a file input element and have a text retrieval method.
A very basic example:
NB. Not all browsers support this code.
[I think Chrome, Firefox and Opera do at time of writing.]
HTML:
<form>
<input type="file" name="thefile" id="thefile" />
</form>
<div id="text"></div>
JS (using jQuery):
$(document).ready(function() {
$('#thefile').change(function(e) {
if (e.target.files != undefined) {
var reader = new FileReader();
reader.onload = function(e) {
$('#text').text(e.target.result);
};
reader.readAsText(e.target.files.item(0));
}
return false;
});
});
Demo: http://jsfiddle.net/FSc8y/2/
If the selected file was a CSV file, you could then process it directly in javascript.
.split() will be useful in that case to split lines and then fields.
the only way I know would be to submit the form to a hidden iframe. this will upload teh file without refreshing the page. you can then use any returned info using javascript. this is what they use for fake ajax style image uploads that let you preview an image before uploading. the truth is it already has been uploaded via a hidden iframe. unfortunately however iframes are not xhtml 1.0 compliant.
something like this article may help:
http://djpate.com/2009/05/24/form-submit-via-hidden-iframe-aka-fake-ajax/
The question you might ask is :
why should I use this method instead of real ajax ?
Well they’re is numereous answer to that but one good reason it that
is doesnt require any type of ajax libs and you can start using it
even if you never used ajax before.
So here it goes.
<form method=”post” action=”formProcess.php” target=”hiddenIFrame”>
<input type=”text” name=”test” /> </form>
<iframe style=”width:0px;height:0px;border:0px;” name=hiddenIFrame />
This is just a normal form but you’ll notice the target in the form
tag, this tells the form to submit in the iframe instead of the
current page.
It’s works exactly as the target attribut on the A tag.
Also the iframe is hidden from the user using
style=”width:0px;height:0px;border:0px;”
now the file formProcess.php is not different from your normal form
processing file but if you want do something on the main page you have
to use JS like that :
window.parent.whatEverYouWannaDoInParentForm();
You can also upload file with this method !
Please checkout the formphp for full example.
Cheers !
Nb : You will see the status bar acts like the page is reloading but
it’s really not.

Categories