Jump to content


Upload Script help


7 replies to this topic

#1 josiec09

    Member

  • Members
  • PipPip
  • 12 posts

Posted 06 August 2010 - 04:49 AM

Ok i am building a php upload script for my image gallery and i am trying to make so if the file exists it will give an error and not upload. I know about "if (!file_exists()) {" but not sure where to add it in my code to get it working...

Any help would be great. Here is my code. Please don't change anything else in my code i will work on making it more Secure later. This is most likely real easy for some people but i am still learning.

<?php
//define a maxim size for the uploaded images in Kb
 define ("MAX_SIZE","1024"); 

//This function reads the extension of the file. It is used to determine if the file  is an image by checking the extension.
 function getExtension($str) {
         $i = strrpos($str,".");
         if (!$i) { return ""; }
         $l = strlen($str) - $i;
         $ext = substr($str,$i+1,$l);
         return $ext;
 }

//This variable is used as a flag. The value is initialized with 0 (meaning no error  found)  
//and it will be changed to 1 if an errro occures.  
//If the error occures the file will not be uploaded.
 $errors=0;
//checks if the form has been submitted
 if(isset($_POST['Submit'])) 
 {
 	//reads the name of the file the user submitted for uploading
 	$image=$_FILES['image']['name'];
 	//if it is not empty
 	if ($image) 
 	{
 	//get the original name of the file from the clients machine
 		$filename = stripslashes($_FILES['image']['name']);
 	//get the extension of the file in a lower case format
  		$extension = getExtension($filename);
 		$extension = strtolower($extension);
 	//if it is not a known extension, we will suppose it is an error and will not upload the file,  
	//otherwise we will do more tests
 if (($extension != "jpg") && ($extension != "jpeg") && ($extension != "png") && ($extension != "gif")) 
 		{
		//print error message
 			echo '<h1>Unknown extension!</h1>';
 			$errors=1;
 		}
 		else
 		{
//get the size of the image in bytes
 //$_FILES['image']['tmp_name'] is the temporary filename of the file
 //in which the uploaded file was stored on the server
 $size=filesize($_FILES['image']['tmp_name']);

//compare the size with the maxim size we defined and print error if bigger
if ($size > MAX_SIZE*1024)
{
	echo '<h1>You have exceeded the size limit!</h1>';
	$errors=1;
}

//we will give an unique name, for example the time in unix time format
$image_name=time().'.'.$extension;
$avatar = $_POST['avatar'];
//the new name will be containing the full path where will be stored (images folder)
$newname="./forums/images/avatars/gallery/".$avatar."/".$image_name;
//we verify if the image has been uploaded, and print error instead
$copied = copy($_FILES['image']['tmp_name'], $newname);
if (!$copied) 
{
	echo '<center>Upload unsuccessfull!</center>';
	$errors=1;
}}}}

//If no errors registred, print the success message
 if(isset($_POST['Submit']) && !$errors)
 {
     echo '<center>Your avatar has been uploaded!<br /><br />

<img src=../../'.$newname.'><br>
To view the Avatar Gallery go to "<a href="/forums/profile.php?mode=editprofile">Edit Profile</a>" go to the Avatar section and click "Show Gallery"!
<a href="/avatar/upload/">Upload</a> another avatar. 
</center>';
} else
include 'form.php';
	
 ?>


#2 josiec09

    Member

  • Members
  • PipPip
  • 12 posts

Posted 06 August 2010 - 05:19 AM

//If no errors registred, print the success message
 if(isset($_POST['Submit']) && !$errors)
 {
     echo '<center>Your avatar has been uploaded!<br /><br />

<img src=../../'.$newname.'><br>
To view the Avatar Gallery go to "<a href="/forums/profile.php?mode=editprofile">Edit Profile</a>" go to the Avatar section and click "Show Gallery"!
<a href="/avatar/upload/">Upload</a> another avatar. 
</center>';

I know this part of the code could be changed to something like this

//If no errors registred, print the success message
 if(!$errors)
 {
     echo '<center>Your avatar has been uploaded!<br /><br />

<img src=../../'.$newname.'><br>
To view the Avatar Gallery go to "<a href="/forums/profile.php?mode=editprofile">Edit Profile</a>" go to the Avatar section and click "Show Gallery"!
<a href="/avatar/upload/">Upload</a> another avatar. 
</center>';

But just leave that alone i will re do some of the code after i get help with what i am asking for.

#3 Shoel

    Administrator

  • Administrators
  • 125 posts

Posted 06 August 2010 - 02:43 PM

Hi josiec09,

Welcome to PHPTalk.com! :)

I assume it is the file at $newname you want to check, right?

There's a number of things that can be improved with your script, but since you explicitly requested no other changes, I will respect that. :)

The check can be done like this:

<?php
// The new name will be containing the full path where will be stored (images folder)
$newname = './forums/images/avatars/gallery/' . $avatar . '/' . $image_name;

// Check if target file exists, copy the file if not.
if (!file_exists($newname)){

  if (!copy($_FILES['image']['tmp_name'], $newname)){
    echo '<center>Upload unsuccessfull!</center>';
    $errors = 1;
  }
}
else {
  echo '<center>File already exists!</center>';
  $errors = 1;
}
?>

On a side note: A general tip that can be worth mentioning is that you should avoid using double quotes for plain strings. If you use double quotes (i.e. "string"), PHP attempts to parse the content of that string for things like variable substitution. This takes more resources, and causes longer execution time. If you use single quotes (i.e. 'string'), PHP handles it as a plain string and makes no attempt to parse it's content.

- S.
Hi there! If you found this post useful, or used this information to help others, we would greatly appreciate a link back to our forum from your website/blog. Thanks! =)

#4 josiec09

    Member

  • Members
  • PipPip
  • 12 posts

Posted 06 August 2010 - 09:11 PM

View PostShoel, on 06 August 2010 - 02:43 PM, said:

Hi josiec09,

Welcome to PHPTalk.com! :)

I assume it is the file at $newname you want to check, right?

There's a number of things that can be improved with your script, but since you explicitly requested no other changes, I will respect that. :)

The check can be done like this:

<?php
// The new name will be containing the full path where will be stored (images folder)
$newname = './forums/images/avatars/gallery/' . $avatar . '/' . $image_name;

// Check if target file exists, copy the file if not.
if (!file_exists($newname)){

  if (!copy($_FILES['image']['tmp_name'], $newname)){
    echo '<center>Upload unsuccessfull!</center>';
    $errors = 1;
  }
}
else {
  echo '<center>File already exists!</center>';
  $errors = 1;
}
?>

On a side note: A general tip that can be worth mentioning is that you should avoid using double quotes for plain strings. If you use double quotes (i.e. "string"), PHP attempts to parse the content of that string for things like variable substitution. This takes more resources, and causes longer execution time. If you use single quotes (i.e. 'string'), PHP handles it as a plain string and makes no attempt to parse it's content.

- S.

Yes $newname was the one i wanted to check. I was able to get it working. Thanks. Also thanks for letting me know about double quotes i will make sure to do that from now on. Also if you have the extra time let me know would else could be improved with my script. I would like to know what i need to work on. ^_^ Thanks again.

#5 Shoel

    Administrator

  • Administrators
  • 125 posts

Posted 07 August 2010 - 03:17 AM

Sure, I'll try to cover the basic points where you can improve - in particular on coding standards:

- Keep data types in mind when defining constant and variables, there's for an example no need to use a string to represent an int/number:

This:

<?php
//define a maxim size for the uploaded images in Kb
 define ("MAX_SIZE","1024"); 
?>
Is better written as:

<?php
// Define a maxim size for the uploaded images in Kb
define('MAX_SIZE', 1024);
?>
- Your indentation is varying greatly, some places you use as much as 9 spaces for a single indentation. Keeping this consistent and at a reasonable number is important for code readability and future maintenance. I would recommend using two spaces, which is pretty much the standard on major projects these days.

That means that this:

<?php
 function getExtension($str) {
         $i = strrpos($str,".");
         if (!$i) { return ""; }
         $l = strlen($str) - $i;
         $ext = substr($str,$i+1,$l);
         return $ext;
 }
?>
Becomes this:

<?php
function getExtension($str){
  $i = strrpos($str,".");
  if (!$i) { return ""; }
  $l = strlen($str) - $i;
  $ext = substr($str,$i+1,$l);
  return $ext;
}
?>
(On a side note, I can also mention that this way of getting the file extension seems rather unnecessary. getimagesize() will provide you with imagetype and mimetype which can be used for validation. (In additon, you also get image dimensions if you would like to enforce a maximum there.))

- You should make sure to space out parameters for function calls properly, with a single space after each separator.

In other words, so that this:

<?php
substr($str,$i+1,$l);
?>
Becomes this:

<?php
substr($str, $i+1, $l);
?>
- Control structures such as if, for, while and so on should always have a space between the control keyword (e.g. if) and the opening parenthesis to distinguish them from function calls.

For an example..

<?php
if(isset($_POST['Submit']))
?>
Should be written as this:

<?php
if (isset($_POST['Submit']))
?>
- Binary operators such as =, !=, == and so on should have a space before and after, so that..

<?php
$errors=0;
?>
Becomes:

<?php
$errors = 0;
?>
- When using string concatenation (i.e. linking string together), you should use a space before and after the dot/period, so that..

<?php
$newname="./forums/images/avatars/gallery/".$avatar."/".$image_name;
?>
Becomes..

<?php
$newname = './forums/images/avatars/gallery/' . $avatar . '/' . $image_name;
?>
- For multi-line comments, the /** style commenting is more suitable:

<?php
//This variable is used as a flag. The value is initialized with 0 (meaning no error  found)  
//and it will be changed to 1 if an errro occures.  
//If the error occures the file will not be uploaded.
?>
Becomes:

<?php
/**
 * This variable is used as a flag. The value is initialized with 0 (meaning no error  found) 
 * and it will be changed to 1 if an errro occures. If the error occures the file will not be uploaded.
 */
?>
- You should be consistent with what kind of block style you use. The two alternatives are:

<?php
if ($foo == $bar)
{
  print 'meh!';
}
?>
Or..

<?php
if ($foo == $bar){
  print 'meh!';
}
?>
I would recommend the latter (last one) because it generally gives better flow/readability in the code, and is the more common style to use these days. Also the standard for most major open source projects. Whatever you do, do not use both / mix them. It will be a mess.

- In some cases it can be sensible to use parenthesis to enclose/separate parts of complex mathematical expressions and similar. In this case however, it is rather unnecessary:

<?php
if (($extension != "jpg") && ($extension != "jpeg") && ($extension != "png") && ($extension != "gif"))
?>
- When you end a hierarchy of blocks enclosed in brackets, do not end them all at the same line like this..

<?php
(...)
if (!$copied) 
{
        echo '<center>Upload unsuccessfull!</center>';
        $errors=1;
}}}}
?>
Instead, you should have one closing bracket at a time - at new lines and a negative indentation that corresponds to the opening bracket of the block you are closing. Like this:

<?php
// Checks if the form has been submitted
if (isset($_POST['Submit'])){
  
  (...)      
  // If it is not empty
  if ($image){
    
    (...)
    if ($extension != 'jpg' && $extension != 'jpeg' && $extension != 'png' && $extension != 'gif'){
      
      (...)
    }
    else {
      
      (...)
      
      // Compare the size with the maxim size we defined and print error if bigger
      if ($size > MAX_SIZE * 1024){
        (...)
      }
      
      (...)
      // Check if target file exists, copy the file if not.
      if (!file_exists($newname)){
      
        if (!copy($_FILES['image']['tmp_name'], $newname)){
          (...)
        }
      }
      else {
        (...)
      }
    }
  }
}
?>
This allows you to trace a closing bracket up to the corresponding control keyword / start of the block, and greatly helps in keeping the stricture clean and simple. Important in regards to avoiding bugs, and less trouble debugging issues.

- Instead of include, you should use require_once() - because this will avoid including the file if it has already been included elsewhere in the code, thus avoiding potential collisions in cases where for an example multiple files/scripts depends on the same function declarations defined within the same include.

- A handy trick for multi-line strings such as blocks of HTML markup, is to use heredoc delimiting. This is done using the operator <<< followed by an identifier, a new line, then the text, and finally the same identifier to close. Example using your markup:

<?php
  echo <<<EOL
<center>Your avatar has been uploaded!<br /><br />
<img src="../../$newname"><br>
To view the Avatar Gallery go to "<a href="/forums/profile.php?mode=editprofile">Edit Profile</a>" go to the Avatar section and click "Show Gallery"!
<a href="/avatar/upload/">Upload</a> another avatar. 
</center>
EOL;
?>

This will behave just like a double-quoted string, meaning you have variable substitution. Thus $newname in the above example will be replaced with the appropriate value. It will also preserve any indentation you add within the text, so that for an example indented HTML is actually outputted the way you wrote it. Another advantage in relation to markup is that there's no need for escaping either quote types, as the string/text is delimited by the identifiers (in my example EOL) instead.

--

I might have missed a few, but it's 5 am where I am in the world.. so time to get some sleep.

Hopefully this should help a little on your journey towards learning PHP anyway. Apart from the coding standard, you seem to be doing reasonably well so far. If you run into any issues, or would like to discuss anything related to web development, you know where to find us. :)

- S.
Hi there! If you found this post useful, or used this information to help others, we would greatly appreciate a link back to our forum from your website/blog. Thanks! =)

#6 josiec09

    Member

  • Members
  • PipPip
  • 12 posts

Posted 07 August 2010 - 04:59 AM

Thanks you very much i was able to fix somethings and clean up my code it looks much better now. (I may post it later on when i am done)

Can you think of any way to do this better.

This code pulls all the directories from "albums" and displays them in a drop down menu. And it ignores the directories "." ".." and the file "description.txt".

<center><form name="newad" method="post" enctype="multipart/form-data">
Max filesize: 1Mb<br>
Allowed filetypes: jpg, jpeg, png, gif
 <table>
 <tr>
   <td><div align="right">Directory:</div></td>
   <td><select name="gallery" id="gallery">
     <?php
if ($handle = opendir('./albums/')) {
    /* loop through directory. */
    while (false !== ($dir = readdir($handle))) {
		if ($dir != ".." && $dir != "." && $dir != "description.txt"){
        echo '<option value='.$dir.'>'.$dir.'</option>';
    }
	}
    closedir($handle);
}
?> 
   </select> 
   (<a href="/gallery/create/">Create</a>)</td>
 </tr>
 	<tr>
 	  <td>Choose image:</td>
 	  <td><input type="file" name="image" id="image"></td>
 	</tr>
 	<tr><td>&nbsp;</td>
 	  <td><input name="Submit" type="submit" value="Upload image"></td>
 	</tr>
 </table>	
</form></center>


#7 Shoel

    Administrator

  • Administrators
  • 125 posts

Posted 07 August 2010 - 05:41 PM

You are very welcome. :)

When it comes to the directory listing, you are not that far from how I would have done it;

(Assuming you are only looking to list the first level of directories... otherwise we'll have to add a recursive check.)

<?php

$dir = './albums';

$ignore = array('.', '..');

// Make sure it's a valid directory before trying to open it
if (is_dir($dir) && $handle = opendir($dir)){
  
  // Walk through the first level of the directory
  while (FALSE !== ($file = readdir($handle))){
    
    // Check against our ignore array, and whether it is a directory or not
    if (!in_array($file, $ignore) && is_dir("$dir/$file")){

      // $file is a first/top level directory within $dir.. do stuff here.
    }
  }
}
?>

- S.
Hi there! If you found this post useful, or used this information to help others, we would greatly appreciate a link back to our forum from your website/blog. Thanks! =)

#8 josiec09

    Member

  • Members
  • PipPip
  • 12 posts

Posted 07 August 2010 - 10:20 PM

Thanks you very much i tried it out and it works. And now i don't have to block out stuff that is not a directory, like the txt file.





1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users