I have set a variable to true if a file upload function is successful

$flag = true;

I would then like an if statement to run a mysqli query only if $flag is true

However the true value is not being recognizing by the if statement, despite it being set to global

function handleUpload() {
    $uploadedTempFile = $_FILES['file_upload']['tmp_name'];
    $filename = basename($_FILES['file_upload']['name']);
    $destFile = UPLOAD_DIRECTORY . $filename;

$isUploadedFile = is_uploaded_file($uploadedTempFile);
$validSize = $_FILES['file_upload']['size'] <= MAXSIZE && $_FILES['file_upload']['size'] >= 0;

if ($isUploadedFile && $validSize && validFileType($uploadedTempFile, $destFile)) {
    $success = move_uploaded_file($uploadedTempFile, $destFile);

    if ($success) {
		global $flag;
		$flag = true;

        $response = 'The file was uploaded successfully!';
    } else {
        $response = 'An unexpected error occurred; the file could not be uploaded.';
    }
} else {
    $response = 'Error: the file you tried to upload is not a valid file. Check file type and size.';
}

return $response;

}

if($flag==true){$query = "INSERT INTO uploads(cat_name, filename, document_name, document_type, description, upload_date, size) ";

  	$query .= " VALUES('{$cat_name}', '{$filename}', '{$document_name}', '{$document_type}', '{$description}', now(), {$size})"; 

 	$create_post_query = mysqli_query($connection, $query);  

  confirmQuery($create_post_query);}

    Do you actually call that function somewhere before you test if $flag is true?

    On a side note, best practices would probably be to pass $flag in as a function parameter -- by reference in this case -- instead of using "global", which tightly links the function to the application code and makes it hard to test and difficult to re-use.

      Please DON'T use the global keyword to get data into/out of a function. It creates spaghetti code that requires you to keep track of every variable you have used global with in your application.

      One of the points of well written function is, the only affect it has on the calling code can be seen by looking at the calling code. You shouldn't need to remember or look up what the code inside the function is doing in order to make use of the result that the function produces.

      This would be a good case where you would define a result object and return that object to the calling code.

      <?php
      
      // define a class that returns an object with two properties, a status (true/false), and a message string
      class function_result
      {
          // property declaration
          public $status = false;
          public $message = '';
      }
      
      function handleUpload() { 
      
      $flag = false;
      $uploadedTempFile = $_FILES['file_upload']['tmp_name']; 
      $filename = basename($_FILES['file_upload']['name']); 
      $destFile = UPLOAD_DIRECTORY . $filename; 
      
      $isUploadedFile = is_uploaded_file($uploadedTempFile); 
      $validSize = $_FILES['file_upload']['size'] <= MAXSIZE && $_FILES['file_upload']['size'] >= 0; 
      
      if ($isUploadedFile && $validSize && validFileType($uploadedTempFile, $destFile)) { 
          $success = move_uploaded_file($uploadedTempFile, $destFile); 
      
          if ($success) { 
              $flag = true; 
              $response = 'The file was uploaded successfully!'; 
          } else { 
              $response = 'An unexpected error occurred; the file could not be uploaded.'; 
          } 
      } else { 
          $response = 'Error: the file you tried to upload is not a valid file. Check file type and size.'; 
      } 
      
      return new function_result($flag,$response); 
      } 
      
      
      // usage -
      $upload = handleUpload();
      
      if($upload->status){
      	$query = "INSERT INTO uploads(cat_name, filename, document_name, document_type, description, upload_date, size) "; 
      
            $query .= " VALUES('{$cat_name}', '{$filename}', '{$document_name}', '{$document_type}', '{$description}', now(), {$size})";  
      
           $create_post_query = mysqli_query($connection, $query);   
      
        confirmQuery($create_post_query);
      }

        I tried the suggested class however received the following error -

        Notice: Trying to get property of non-object in C:\pathtofile\process_add_file.php on line 102

          Is line 102 this line?

          pbismad wrote:

          return new function_result($flag,$response);

          If your answer is "yes", what's your PHP version?

          Otherwise, show us the relevant code from lines 102 and before/after, etc.

            I am now receiving the following error

            Catchable fatal error: Object of class function_result could not be converted to string in C:\pathtofile\process_add_file.php on line 155

            Please see full script below
            Comment added to line 155 // THIS IS LINE 155

            define('UPLOAD_DIRECTORY', '../upload/');
            define('MAXSIZE', 5242880); // 5MB in bytes.
            
            // Before PHP 5.6, we can't define arrays as constants.
            $ALLOWED_EXTENSIONS = array('pdf', 'doc', 'docx', 'jpg', 'jpeg');
            $ALLOWED_MIMES = array('application/pdf', // For .pdf files.'application/msword', // For .doc files.
                'application/vnd.openxmlformats-officedocument.wordprocessingml.document', // For .docx files.
               	'image/jpeg',
            );
             if(isset($_POST['upload'])) {
            
            		$document_name  	= escape($_POST['document_name']);
            		$cat_name  			= escape($_POST['cat_name']);
                    $document_type      = escape($_POST['document_type']);
            		$description        = escape($_POST['description']);
            		$upload_date        = escape(date('d-m-y'));
            		$size 				= $_FILES['file_upload']['size'];
            		$filename           = escape($_FILES['file_upload']['name']);
            
            
            
            /**
             * Checks if given file's extension and MIME are defined as allowed, which are defined in
             * array $ALLOWED_EXTENSIONS and $ALLOWED_MIMES, respectively.
             *
             * @param $uploadedTempFile The file that is has been uploaded already, from where the MIME
             *     will be read.
             * @param $destFilePath The path that the dest file will have, from where the extension will
             *     be read.
             * @return True if file's extension and MIME are allowed; false if at least one of them is not.
             */
            
            
            
            function validFileType($uploadedTempFile, $destFilePath) {
                global $ALLOWED_EXTENSIONS, $ALLOWED_MIMES;
            
            $fileExtension = pathinfo($destFilePath, PATHINFO_EXTENSION);
            $fileMime = mime_content_type($uploadedTempFile);
            
            $validFileExtension = in_array($fileExtension, $ALLOWED_EXTENSIONS);
            $validFileMime = in_array($fileMime, $ALLOWED_MIMES);
            
            $validFileType = $validFileExtension && $validFileMime;
            
            return $validFileType;
            }
            
            /**
             * Handles the file upload, first, checking if the file we are going to deal with is actually an
             * uploaded file; second, if file's size is smaller than specified; and third, if the file is
             * a valid file (extension and MIME).
             *
             * @return Response with string of the result; if it has been successful or not.
             */
            class function_result
            {
                // property declaration
                public $status = false;
                public $message = '';
            }
            
            function handleUpload() { 
            
            $flag = false;
            $uploadedTempFile = $_FILES['file_upload']['tmp_name']; 
            $filename = basename($_FILES['file_upload']['name']); 
            $destFile = UPLOAD_DIRECTORY . $filename; 
            
            $isUploadedFile = is_uploaded_file($uploadedTempFile); 
            $validSize = $_FILES['file_upload']['size'] <= MAXSIZE && $_FILES['file_upload']['size'] >= 0; 
            
            if ($isUploadedFile && $validSize && validFileType($uploadedTempFile, $destFile)) { 
                $success = move_uploaded_file($uploadedTempFile, $destFile); 
            
                if ($success) { 
                    $flag = true; 
                    $response = 'The file was uploaded successfully!'; 
                } else { 
                    $response = 'An unexpected error occurred; the file could not be uploaded.'; 
                } 
            } else { 
                $response = 'Error: the file you tried to upload is not a valid file. Check file type and size.'; 
            } 
            
            return new function_result($flag,$response); 
            } 
            
            
            
            $upload = handleUpload();
            
            if($upload->status){
                $query = "INSERT INTO uploads(cat_name, filename, document_name, document_type, description, upload_date, size) "; 
            
                  $query .= " VALUES('{$cat_name}', '{$filename}', '{$document_name}', '{$document_type}', '{$description}', now(), {$size})";  
            
                 $create_post_query = mysqli_query($connection, $query);   
            
              confirmQuery($create_post_query);
            } 
            
            
            // Flow starts here.
            
            $validFormSubmission = !empty($_FILES);
            
            if ($validFormSubmission) {
                $error = $_FILES['file_upload']['error'];
            
            switch($error) {
                case UPLOAD_ERR_OK:
                    $response = handleUpload();
                    break;
            
                case UPLOAD_ERR_INI_SIZE:
                    $response = 'Error: file size is bigger than allowed.';
                    break;
            
                case UPLOAD_ERR_PARTIAL:
                    $response = 'Error: the file was only partially uploaded.';
                    break;
            
                case UPLOAD_ERR_NO_FILE:
                    $response = 'Error: no file could have been uploaded.';
                    break;
            
                case UPLOAD_ERR_NO_TMP_DIR:
                    $response = 'Error: no temp directory! Contact the administrator.';
                    break;
            
                case UPLOAD_ERR_CANT_WRITE:
                    $response = 'Error: it was not possible to write in the disk. Contact the administrator.';
                    break;
            
                case UPLOAD_ERR_EXTENSION:
                    $response = 'Error: a PHP extension stopped the upload. Contact the administrator.';
                    break;
            
                default:
                    $response = 'An unexpected error occurred; the file could not be uploaded.';
                    break;
            }
            } else {
                $response = 'Error: the form was not submitted correctly - did you try to access the action url directly?';
            }
            
            echo $response;      // THIS IS LINE 155
             }
            

              // Flow starts here.

              That would be an incorrect comment in your code.

              This code is disorganized. You are trying to run the INSERT query before you have validated any of the data. You also apparently copied the example usage I posted, which didn't have any knowledge of and therefore didn't match the context of how your code was using the handleUpload() function, without altering your existing code to match the changes that were given.

              You need to organize your code with any initialization/definitions (including any class/function definitions) first, then process the form inputs, and then produce output. Your form processing code should be all together and only contain the logic flow that it uses to perform its tasks.

              Next, to allow your form processing code to validate more than one input, you should use an array to hold the validation error messages. This array will also serve as a an error flag. If the array is empty, there are no errors. If the array is not empty, there are errors. Only after you have validated all the inputs should you use the submitted data.

              I can almost guarantee that your escape() function can fail to protect against sql injection in some cases. You should use a prepared query with bound input parameters to supply data to your sql query statement. If you do escape your data, you should only do it immediately before using it in your sql query statement. If you escape it before validating it, the value can be altered which can affect the result of the validation.

              Since this code is dealing with an uploaded file, there is a case where the file size is larger than the post_max_size setting and the $POST and $FILES arrays will be empty. In this case, your if(isset($POST['upload'])) { will be false and your code will be skipped over. Your form processing code must detect that a post method form was submitted, use - if($SERVER['REQUEST_METHOD'] == 'POST') {, then check for the case where both the $POST and $FILES arrays are empty to handle this error.

              Lastly, when validating user input, you should produce a unique and helpful error message for each different thing that can go wrong, as long as you don't divulge security related information, so that the user can correct the problems that he has control over. For code/server problems, you should output a generic message to the user, but log the actual reason why something failed.

                I do have a correction to the class code I posted above. It needs a constructor to set the properties -

                class function_result 
                { 
                    // property declaration 
                    public $status = false; 
                    public $message = '';
                
                public function __construct($status,$message)
                {
                	$this->status = $status;
                	$this->message = $message;
                }
                } 

                  You failed to alter line 155 to take into account the fact that your response is no longer a string (except when it is a string - you'll want to think about that as well).

                    Thanks for all of the helpful advice it has given me an insight into lots of things I need to know and study.

                    You mentioned that I should take into account the fact that response is no longer a string.
                    The error message I am receiving now is -

                    Catchable fatal error: Object of class function_result could not be converted to string in C:\pathtofile\process_add_file.php on line .....

                    Can you tell me how to deal with this please?

                      The current issue is, you are calling the handleUpload() function in another place than the example usage I gave. It is this second call to the function that's causing the current error, because your code is based on the function only returning the message, which it is no longer doing. You must alter your code to just call the function once, then use the result object that is returned from that function. This will require that you reorganize your code.

                      Your form processing code needs to do these things -

                      1) check that a post method form was submitted
                      -- 2) check the uploaded file for errors
                      ---- 3) validate the uploaded file information - extension, mime-type, file size
                      ------ 4) move the uploaded file
                      -- 5) validate the $_POST form field values

                      -- 6) if there are no errors in any of the above, insert the data into the database

                      I looked at your code more thoroughly, to see what it would take to show you the suggestions that I made, and the code apparently started out as all main code, but got some function definitions thrown around sections of it, and now you are trying to make it 'work'. This is not how to design code. When you design a function, you need to define what the inputs to the function are, what processing the function will do, and what result the function will produce and return to the calling code.

                      Specifically, for your handleUpload function -

                      1) The input(s) to this function should be the $_FILES['file_upload'] array. This will make the function general purpose and allow it to operate on any uploaded file, regardless of the name that was given to the file form field.

                      2) The function should only handle moving the uploaded file. Checking the file size and checking the file extension/mime-type are validation steps and should be complete before ever calling the handleUpload() function.

                      3) Since moving the file can either be successful or it can fail, and you want to return two different failure messages, you need a method of returning more than one value. This is where the result object class comes in.

                      Your function definition should look more like this -

                      function handleUpload($f) {  
                      
                      $flag = false; 
                      $uploadedTempFile = $f['tmp_name'];  
                      $filename = basename($f['name']);  
                      $destFile = UPLOAD_DIRECTORY . $filename;  
                      
                      if(!is_uploaded_file($uploadedTempFile)){
                      	// this actually means someone got a file into the uploaded temp folder without uploading it using the form
                          $response = 'Error: the file you tried to upload is not a valid uploaded file.';
                      } else {
                      	$success = move_uploaded_file($uploadedTempFile, $destFile);
                          if ($success) {  
                              $flag = true;  
                              // $response = 'The file was uploaded successfully!'; // a true status value means the file was moved, any success message should be handled by the calling code
                          } else {  
                              $response = 'An unexpected error occurred; the file could not be uploaded.';  // this is usually due to a path problem or a permission problem
                      		trigger_error('call to move uploaded file failed'); // this is an internal error and you should log all available information about it. i have shown only a simple message in this example.
                          }  
                      }
                      return new function_result($flag,$response);
                      }

                      You would call it and use the returned information like this (this example code uses the $errors array as described in reply #7 in this thread) -

                      	// if all the upload file validation tests passed, you can do something with the uploaded file
                      	if(empty($errors)){
                      		$upload = handleUpload($_FILES['file_upload']); // pass the array of uploaded file info to the function
                      		if(!$upload->status)
                      		{
                      			// handling the file failed
                      			$errors['upload'][] = $upload->message; // add the message that the function produced to the $errors array.
                      		}
                      	}

                      If this step fails, an error is added to the $errors array. This would be used later when deciding to insert the data into the database -

                      	// done with all validation, if no errors use the form data
                      	if(empty($errors))
                      	{
                                      // the code for the INSERT query would go here...
                              }
                        Write a Reply...