Forum Moderators: coopster
I found a script to upload photos into a database. Works great. Problem is I can't update my database "users" so that the value from $imagename updates my database field "photo_filename". The previous value for photo_filename remains unchanged.
I tried echo "<pre>"; print_r($_SESSION); to see if the login values were being passed. It gave me:
Array
(
[user] => Jones
[pass] => 123abc
[code] => 1
)
so I know the password and lastname values for the user are being passed to the page. However, I can't get those values in the Update query. I typed 123abc into the query just to see if it works, and photo_filename was immediately updated.
1) How do I get the query to use the array values to SET photo_filename = '$imagename' WHERE password=[pass] and lastname=[user)? How is the query written (I've tried dozens of different ways after searching the Internet, none worked)?
2) When I used echo "<pre>"; print_r($_SESSION); I got a warning.
Warning: Cannot modify header information - headers already sent by (output started at /home/site/public_html/folder/upload.php:5) in /home/site/public_html/folder/upload.php on line....
This line corresponds to:
header('Location: ' . $uploadSuccess);
What do I need to do?
3) The way the script is written, the photo is named something like 1181177664-mypic.jpg. I would prefer if the photos were named according to the userid in a row of the database (ex: 1.jpg, 2.gif) where userid of Jones is 1, userid of Smith is 2. That way the number in the photo name would be unique for each individual member and could be overwritten if that member decides to reupload a new photo. The way the script is written now, one member can upload dozens of photos, and though only the most current name is entered into the database, dozens can be sitting in a folder on my website for each member. How would I change this script to accomplish this?
Thanks so much.
upload.php
<?php
include("security.php");
include("config.php");
// make a note of the current working directory, relative to root.
$directory_self = str_replace(basename($_SERVER['PHP_SELF']), '', $_SERVER['PHP_SELF']);
// make a note of the directory that will recieve the uploaded files
$uploadsDirectory = $_SERVER['DOCUMENT_ROOT'] . $directory_self . 'photos/';
// make a note of the location of the upload form in case we need it
$uploadForm = 'http://' . $_SERVER['HTTP_HOST'] . $directory_self . 'upload.form.php';
// make a note of the location of the success page
$uploadSuccess = 'http://' . $_SERVER['HTTP_HOST'] . $directory_self . 'upload.success.php';
// name of the fieldname used for the file in the HTML form
$fieldname = 'file';
// Now let's deal with the upload
// possible PHP upload errors
$errors = array(1 => 'php.ini max file size exceeded',
2 => 'html form max file size exceeded',
3 => 'file upload was only partial',
4 => 'no file was attached');
// check the upload form was actually submitted else print form
isset($_POST['submit'])
or error('the upload form is neaded', $uploadForm);
// check for standard uploading errors
($_FILES[$fieldname]['error'] == 0)
or error($errors[$_FILES[$fieldname]['error']], $uploadForm);
// check that the file we are working on really was an HTTP upload
@is_uploaded_file($_FILES[$fieldname]['tmp_name'])
or error('not an HTTP upload', $uploadForm);
// validation... since this is an image upload script we
// should run a check to make sure the upload is an image
@getimagesize($_FILES[$fieldname]['tmp_name'])
or error('only image uploads are allowed', $uploadForm);
// make a unique filename for the uploaded file and check it is
// not taken... if it is keep trying until we find a vacant one
$now = time();
while(file_exists($uploadFilename = $uploadsDirectory.$now.'-'.$_FILES[$fieldname]['name']))
{
$now++;
}
//name var for image
$imagename = $now.'-'.$_FILES[$fieldname]['name'];
// now let's move the file to its final and allocate it with the new filename
@move_uploaded_file($_FILES[$fieldname]['tmp_name'], $uploadFilename)
or error('receiving directory insuffiecient permission', $uploadForm);
// If you got this far, everything has worked and the file has been saved.
// We are now going to redirect the client to the success page.
$sql = "UPDATE users SET photo_filename = '$imagename' WHERE password='$password'";
mysql_query($sql);//run the query
header('Location: ' . $uploadSuccess);
// make an error handler which will be used if the upload fails
function error($error, $location, $seconds = 5)
{
header("Refresh: $seconds; URL=\"$location\"");
echo '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"'."\n".
'"http://www.w3.org/TR/html4/strict.dtd">'."\n\n".
'<html lang="en">'."\n".
'<head>'."\n".
'<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">'."\n\n".
'<link rel="stylesheet" type="text/css" href="stylesheet.css">'."\n\n".
'<title>Upload error</title>'."\n\n".
'</head>'."\n\n".
'<body>'."\n\n".
'<div id="Upload">'."\n\n".
'<h1>Upload failure</h1>'."\n\n".
'<p>An error has occured: '."\n\n".
'<span class="red">' . $error . '...</span>'."\n\n".
' The upload form is reloading</p>'."\n\n".
' </div>'."\n\n".
'</html>';
exit;
} // end error handler
?>
Warning: Cannot modify header information - headers already sent by...
My PHP is a little rusty, but I don't see any place where you assigned a value to $password. Are session variables auto-loaded into your local scope? (I'm guessing not.)
Tru changing your mysql_query($sql) line to print($sql) and see what $sql actually has in it. I bet it's not what you think.
After that, I think you have a logic bomb in your sql query. I haven't fully read your code, but I am pretty sure something is wrong with your WHERE clause.
Password not assigned:
$password = $_SESSION['pass'];
$user_name = $_SESSION['user'];
The query might look similar to the following
$sql = "UPDATE users SET photo_filename = '$imagename' WHERE password='$password' AND username = '$username'";
Habtom
Slade, so when I remove the line: echo "<pre>"; print_r($_SESSION); I will no longer have the problem? Good news. I wasn't aware that the error occurs when something is printed. Thanks for educating me.
Habtom, it is nice to hear from you again. As you can see, I actually learned the echo "<pre>"; print_r($_SESSION); trick from you on another post you helped me with. Thanks for teaching me.
Habtom, your code was very similar to something I tried but I can't remember if $_SESSION was part of the line. Anyway, your code worked. I added:
$password = $_SESSION['pass'];
$lastname = $_SESSION['user'];
$sql = "UPDATE users SET photo_filename = '$imagename' WHERE password='$password' AND lastname = '$lastname'";
Lo and behold the photo_filename is now updated. Thank you, thank you. Thanks for being so patient with a php beginner.
Now as for my third question, would I have to pass the userid on login and add $userid = $_SESSION['userid']; to the page? Then I guess I have to change this:
// make a unique filename for the uploaded file and check it is
// not taken... if it is keep trying until we find a vacant one
$now = time();
while(file_exists($uploadFilename = $uploadsDirectory.$now.'-'.$_FILES[$fieldname]['name']))
{
$now++;
}
//name var for image
$imagename = $now.'-'.$_FILES[$fieldname]['name'];
I guess I wouldn't need the first paragraph as the userid will already make the photo name unique (examples: 1.jpg, 2.gif).
As far as setting the $imagename, I guess it would = to the passed value of $userid, but what about the extensions? Since they won't be the same each time (gif, jpeg, jpg) how is that coded?
Am I on the right track, or is there a better way?
It would be rare, so I completely understand why the timestamp was used in the script I posted. What I am concerned with is that each member can upload dozens of photos (maybe more), even though only one photo name is stored in the database and being used by that member. All of those extra photos will be uploaded to a folder on my site and living there, with no way for me to delete the ones not being used, as I can't identify the used ones from the unused ones. This is because a member is not overwriting their previous photo (since the photo name is not the same each time for that particular member).
What do you mean by unlink the name in the database? Only one photo filename is in the database for each person (update database takes care of that).
How would I delete the names from the directory that are not in the database?
[edited by: oceanwave at 1:41 pm (utc) on June 8, 2007]
I saw this:
unlink
(PHP 4, PHP 5)
unlink — Deletes a file
Description
bool unlink ( string $filename [, resource $context] )
-------------
unlink($photo_filename) or print "Unable to unlink $photo_filename ($!)\n" ;
Is this correct? Where do I put this in the script? Where is the file being deleted from? Is it the filename in the database or the file in the folder on the website?
the steps will be as I mentioned
// you can change this to any directory you want
// as long as php can write to it
$uploadDir = 'files/';
if(isset($_POST['upload']))
{
$comments = $_POST['mtxComments'];
$fileName = $_FILES['userfile']['name'];
$tmpName = $_FILES['userfile']['tmp_name'];
$fileSize = $_FILES['userfile']['size'];
$fileType = $_FILES['userfile']['type'];
if(!$_POST['mtxComments']) die('Alert: Comments field was blank.');
// get the file extension first
$ext = substr(strrchr($fileName, "."), 1);
// generate the random file name
$randName = md5(rand() * time());
// and now we have the unique file name for the upload file
$filePath = $uploadDir . $randName . '.' . $ext;
// move the files to the specified directory
// if the upload directory is not writable or
// something else went wrong $result will be false
$result = move_uploaded_file($tmpName, $filePath);
if (!$result) {
echo "Error uploading file";
exit;
}
require_once($_SERVER['DOCUMENT_ROOT'].'/db_connect.php');
if(!get_magic_quotes_gpc())
{
$fileName = addslashes($fileName);
$filePath = addslashes($filePath);
$comments = addslashes($comments);
}
$query = "INSERT INTO tablename (name, size, type, path, comments ) ".
"VALUES ('$fileName', '$fileSize', '$fileType', '$filePath', '$comments')";
mysql_query($query) or die('Error, query failed : ' . mysql_error());
echo "<br>File uploaded<br>";
}
?>
as it shows i only used to save details of the file on the database but the actual file is saved on the server. when i needed to delete a file i did the following.
if (isset($_GET['deleteNotes']) && isset($_GET['notes']) ) {
$id = $_GET['notes'];
$result = mysql_query("SELECT * FROM tablename WHERE id = $id")
or die('Delete file failed. ' . mysql_error());
if (mysql_num_rows($result) == 1) {
$row = mysql_fetch_assoc($result);
$name = $row['name'];
$path = $row['path'];
unlink($path);
$result = mysql_query("DELETE FROM tablename
WHERE id = $id")
or die('Delete file failed. ' . mysql_error());
// file deleted successfully, let the user know about it
echo "<p align=center>File '$name' has been deleted successfully.</p>";
} else {
echo "<p align=center>Cannot delete a non-existing file..</p>";
}
}
The above code deletes the row from the table which saved the file details orginally such as size name etc. it then uses the unlink to delete the file from the server.
The reason i saved files on the server was purely for speed of processing and because i was having problems with saving it in the database.
Hope this helps mate. Try using bits of it in your code.
I tried this (with and without the period):
if (unlink($uploadsDirectory.$photo_filename)) {
print "Deleted $photo_filename!\n";
} else {
print "Delete of $photo_filename failed!\n";
}
I tried this (with and without the period):
unlink($uploadsDirectory.$photo_fileName);
I tried other bits of code found during my Google searches. Nothing has worked.
By the way, was I correct to use $uploadsDirectory as the path (based upon the script I posted)?
Jatar_k has been so patient explaining where in the script to post the unlink code. I'm still not sure where that is in the script I posted. I know I placed the code in the wrong places, because I got an assortment of error messages including "Warning: Division by zero unlink", no such file or directory...., etc.
Thank you phlogit for posting your code. I will have to study it a bit longer to understand it. I don't want to delete a row in my database - just remove the extra photos in my photos folder. I will try to find the bits of code that apply to my situation. Thanks again.
I'm sorry to say, I still need help.
$sql = "UPDATE users SET photo_filename = '$imagename' WHERE password='$password'";
mysql_query($sql);//run the query
that is your update query.
You will need to add
a select query to get the name of the old image, if there is one
use the data from the photo_filename column and build a path to where the image actually lives
then use that path with unlink to delete the old image
then carry on with the code as it is now. I don't like it using password as the way to identify the row, is there nothing else unique you could use, like user id? Keep in mind that passwords may not be unique and should never be treated as such. I'll make my example with password but you should really look into that
all of the above might look something like this
$q = "select * from users where password='$password'";
$query = mysql_query($q) or die ('select old image query died: ' . mysql_error());
// because this should only return a single row I will use an if
if ($row = mysql_fetch_array($query)) {
$oldimg = $row['photo_filename'];
}
$oldimg = $uploadsDirectory . $oldimg;
unlink($oldimg);
$sql = "UPDATE users SET photo_filename = '$imagename' WHERE password='$password'";
mysql_query($sql);//run the query
something like that, not totally sure I am using the right things from the right places but it will be pretty close
Your code works perfectly!
Could you please explain this part:
---------
$oldimg = $row['photo_filename'];
}
$oldimg = $uploadsDirectory . $oldimg;
---------
How can $oldimg equal just the filename AND also equal the path with the filename?
I guess you had to use $row to get the field information from the database. Could you please tell me why this is written in two steps instead of something that combines the two like $uploadsDirectory . $row['photo_filename'];
I understand your concern about using the password (with lastname). It is bothering me too. I am using a tutorial script that I have been trying to edit. The login page asks for lastname and password. I will have to change the information that is passed into the session to include userid.
Thank you, thank you jatar_k! I had never heard of "unlink", and had no idea that you could delete files from a website folder while changing your database at the same time. Remarkable!
Thanks to everyone for their patience.
:) May be I explain this part for you. The only part I think you have missed is the dot (.) That is like attaching one part of the code to the other. An example:
$i = "AB";
$j = "CD";
$i = $i.$j;
echo $i; gives you the result "ABCD"
Habtom
Read the PHP manual section on SQL Injection for more information.
The function mysql_escape_string() does the job for MySQL.
(Don't rely on magic_quotes, by the way. They're an inelegant hack.)
Alfaguru, thank you for responding. I looked up mysql_escape_string(). One post said to use mysql_real_escape_string instead. Is this true (php5)?
Would the code look like this in the script? I never know where to put the code - not sure if it should be before or after the query is run - not sure if it should have two )); at the end like the example I found.
-----
$sql = "UPDATE users SET photo_filename = '$imagename' WHERE password='$password' AND lastname = '$lastname'";
mysql_real_escape_string($password),
mysql_real_escape_string($lastname));
mysql_query($sql);//run the query
header('Location: ' . $uploadSuccess);
$imagename = mysql_real_escape_string(trim($imagename));
$lastname = mysql_real_escape_string(trim($lastname));
$password = mysql_real_escape_string(trim($password));
$sql = "UPDATE users SET photo_filename = '$imagename' WHERE password='$password' AND lastname = '$lastname'";
mysql_query($sql);//run the query
header('Location: ' . $uploadSuccess);
And no, it shouldn't have "))", I don't see any reason for that.
Habtom
My new problem is not with the script, but rather with what I am trying to do. A user enters information in a form, without their image, and submits the info to the database. I originally set the photo_filename field to automatically insert the name soon.jpeg when the form was submitted (there was a soon.jpeg image in a "photos" folder on my website - "photo coming soon"). Everyone initially had the "photo coming soon" image until they went into their user panel and updated their information. Now that worked fine, until I decided I needed to overwrite the extra images in the photos folder so there wouldn't be dozens for each user (the whole reason for posting this thread). I then changed my script (as outlined throughout this thread).
The problem was when the first user updated their info, the soon.jpeg was deleted from the folder - not good for everyone else. So I then had the form name each person's photo_filename field using the now() function with a .jpeg extension (like 2007-6-13-19-45-43.jpeg). Now everyone has a different photo_filename after they submit the form.
I bet you can guess the problem. When the user updates/uploads their photo for the first time, the unlink function can't get rid of 2007-6-13-19-45-43.jpeg in the "photos" folder, because it never existed there to begin with. So I now get an error message like:
-----
Warning: unlink(/home/mysite/public_html/folder/photos/2007-6-13-19-45-43.jpeg) [function.unlink]: No such file or directory in /home/mysite/public_html/folder/upload.php on line 82
Warning: Cannot modify header information - headers already sent by (output started at /home/mysite/public_html/folder/upload.php:82) in /home/mysite/public_html/folder/upload.php on line 92
-----
However, the new photo_filename name is added to the database and the new photo is uploaded to the photos folder, despite the warnings. Of course, the warnings only happen the first time a user tries to change their photo because after that, the photo actually exists in the folder, and can be overwritten.
In a nutshell, when the form is submitted an image is not added to the photos folder. Since the image does not exist in the photos folder, it can't be unlinked during the first update.
I don't want my users to get those nasty warnings. Any suggestions? What exactly do I need to change in the script?
The quick way, I think this should do it:
@unlink($path);
The "@" suppresses errors.
The Best Way I think is to check if the file exits, and if it does to unlink:
if (file_exists($path)) {
unlink($path);
}
Check the file_exists [php.net] function.
Habtom