Welcome Guest, Not a member yet? Register   Sign In
Randomly generated string seems to be the same if functions are called at very similar times
#1

[eluser]Dandy_andy[/eluser]
I've designed a photo upload page for my website and everything works fine. Images uploaded are stored in a directory that has a randomly generated path. However, when multiple users are trying to upload photos at the same time, the system seems to generate the same path. To overcome this, I've added an extra function to check the path first and see if an image already exist, in which case it adds an extra '1' onto the end of the file path. I was wondering whether this is caused by some caching issue because it only occurs if files are uploaded from different machines at the same time?

Code:
//upload photo file
public function upload_file() {
  
  $this->load->model('image_file');
  $mem_id = $this->session->userdata('mem_id');
  
  $string = $this->image_file->string_generate();
  $set_image_path = $this->image_file->set_image_path($string);
  
  //check if image exists in directory with same string (unlikely but better safe than sorry!)
  if (file_exists($set_image_path.$string.'.jpeg')) {$string .= '1';}
  
  $config['upload_path'] = $set_image_path;
  $config['allowed_types'] = 'gif|jpg|jpeg|png';
  $config['max_size'] = '4000';
  $config['max_width'] = '6000';
  $config['max_height'] = '4000';
  $config['file_name'] = $string.'.jpeg';
  $this->load->library('upload', $config);
  
  //create the directory
  mkdir($set_image_path, 0644, true);

  //do upload & process image (rezize and rename)
  $this->upload->do_upload('userphoto');
  $results = $this->upload->data();
  $error = $this->upload->display_errors('', '');
  
  if (($error) or (!$this->image_file->check_file_exists($set_image_path.$string.'.jpeg'))) {
   $this->session->set_flashdata('error', $error);
   redirect('user/upload_photo');
   }
  
  //write the data to the photo db
  $this->image_file->write_imagedata($mem_id, $string, $set_image_path);
  
  //load image library
  $this->load->library('image_lib');
  
  
  $config['image_library'] = 'gd2';
  $config['source_image'] = $set_image_path.$string.'.jpeg';
  $config['create_thumb'] = TRUE;
  $config['maintain_ratio'] = TRUE;
  $config['quality'] = 50;
  $config['width'] = 160;
  $config['height'] = 120;
  $this->image_lib->initialize($config);
  $this->image_lib->resize();
  
   //error check
   if (! $this->image_lib->resize()) {
   $error = $this->image_lib->display_errors('', '');
   $this->session->set_flashdata('error', $error);
   redirect('user/upload_photo');
   }
   else
    {
   $this->load->library('Notificationmssgs');
   $notification = $this->notificationmssgs->notifications();
   $this->session->set_flashdata('message', $notification[3]);
   }
  
  $this->image_lib->clear();
  
  $config['image_library'] = 'gd2';
  $config['source_image'] = $set_image_path.$string.'.jpeg';
  $config['create_thumb'] = FALSE;
  $config['maintain_ratio'] = TRUE;
  $config['quality'] = 50;
  $config['width'] = 560;
  $config['height'] = 420;
  $this->image_lib->initialize($config);
  $this->image_lib->resize();
  $this->image_lib->clear();
      
  redirect('user/upload_photo');

}//function submit profile

And the relevant model functions are:-

Code:
//set image path (generate random code which will also form filename)
public function set_image_path($string) {

  $pos = 6;
  $f = substr($string, 0, $pos);
  $first = chunk_split($f,2,"/");
  $photo_path = 'photos/'.$first;

  return $photo_path;

}


//check a file exists in the directory
function check_file_exists($path) {

if (file_exists($path)) {return true;} else {return false;}

}


//write image data to photo db
public function write_imagedata($mem_id, $string) {

  $this->load->helper('date');
  $datetime = unix_to_human(time(), TRUE, 'eu');
  
  //check to see if user already has an image in their photos db. If not, also copy the path of upload image to members db
  $this->db->where('mem_id', $mem_id);
  $this->db->from('photos');
  if ($this->db->count_all_results() <= 0) {$dbdata = array('photo_path' => $string, 'approved' => '0'); $this->db->where('mem_id', $mem_id); $this->db->update('members', $dbdata);}
  
   $dbdata = array(
   'mem_id' => $mem_id,
   'photo_path' => $string,
   'approved' => 0,
   'main' => 0,
   'votes' => 0,
   'rating' => 0,
   'voting' => 1,
   'posted' => $datetime,
   'pho_caption' => ''
  
   );
  
  $this->db->insert('photos',$dbdata);
}
#2

[eluser]yacman[/eluser]
Where is the code for
Code:
$this->image_file->string_generate();

This model call is not referenced and is what generates your file name (the actual part that is being duplicated).

My guess is your string_generate() is time based, and yes people can make simultaneous requests.

To avoid this, try to isolate users to their own working folders. Instead of uploading to /upload/
use
/upload/[user-id]/ or some unique value that isn't replicated across user sessions.

#3

[eluser]Dandy_andy[/eluser]
Here is the code for the string_generate:-
Code:
//generate random string for filename and path
public function string_generate() {

  $chars = "abcdefghijklmnopqrstuvwxyz0123456789";
  $size = strlen($chars);
  $string = '';  
  for ($i = 0; $i < 15; $i++) {  
  $string .= $chars[rand(0, $size - 1)];  
   }
  return $string;

}

I can see that the rand() function will be time based and could generate the same string if images are uploaded at the same time. In fact, on testing, the images with the same paths are ones which have exactly the same time in miliseconds as each other. I need to have the images in random folders to avoid any chance of people people able to find out where particular images are stored. What I am doing now is to add an additional few characters onto the end of the string that are user specific so that if images are uploaded at the same time, then chance of them having the same filename is very very slim.

Thanks for your comment.
#4

[eluser]rogierb[/eluser]
rand() is not a very random funtion. It is better to use mt_rand().

Another idea is to do a shuffle() on $chars to make the order more random
<code>
$chars = "abcdefghijklmnopqrstuvwxyz0123456789";

//randomize characters
$chars = str_split($chars);
shuffle($chars);
$chars = implode('', $chars);

</code>
#5

[eluser]Dandy_andy[/eluser]
Thank 'rogierb'. I'll give that a go.

I think that coupled with the additional characters specific to the user at the end of the string should see me safe. On tests, it seems to be working fine.

Just curious to know what the main difference between rand() and mt_rand() is? I understand that they both generate random numbers using different algorithms?
#6

[eluser]rogierb[/eluser]
yeah, rand() uses the older libc library. mt_rand() uses a different (faster) algorithm based on the Mersenne Twister (mt).
It produces a better random number alhough anything generated by code is pseudo random.

Something like random.org provides true random number. There are more services out there like them




Theme © iAndrew 2016 - Forum software by © MyBB