0

I am using Heroku for creating my website, as part of it, there is the ability to upload videos to the site. I have got it sort of working but I am struggling to get one last part working. As I have understood for uploading videos, the name of the file is uploaded to the database whilst the actual video itself is uploaded to a folder defined by myself. I have got it working so the video name is uploaded to the database but the video is not saving to the video folder I have created.

This is the code I have:

<?php
session_start();
require_once('../../includes/config.php');
require('../../vendor/autoload.php');

if(!isset($_SESSION['loggedin'])){ //if login in session is not set
    header("Location: ../../index.php");
}

if($_SESSION['role'] !="admin") {
    header("Location: ../../index.php");
}
  if(isset($_POST["submit"])) {


    //collect form data

    extract($_POST);


    $allowedExts = array("ogg", "mp4", "wma");
    $extension = pathinfo($_FILES['video']['name'], PATHINFO_EXTENSION);

    if ((($_FILES["video"]["type"] == "video/mp4")
        || ($_FILES["video"]["type"] == "video/ogg")
        || ($_FILES["video"]["type"] == "video/wma")

        && ($_FILES["video"]["size"] < 16000000 )
        && in_array($extension, $allowedExts))){ 


        if ($_FILES["video"]["error"] > 0)
        {
            echo "Return Code: " . $_FILES["video"]["error"] . "<br />";
        }


        else
        {
            echo "Upload: " . $_FILES["video"]["name"] . "<br />";
            echo "Type: " . $_FILES["video"]["type"] . "<br />";
            echo "Size: " . ($_FILES["video"]["size"] / 1024) . " Kb<br />";
            echo "Temp file: " . $_FILES["video"]["tmp_name"] . "<br />";
           $upload =  $_FILES["video"]["name"];

            if (file_exists("../videos/" . $_FILES["video"]["name"]))
            {
                echo $_FILES["video"]["name"] . " already exists. ";
            }
            else
            {
                move_uploaded_file($_FILES["video"]["tmp_name"],
                    "../videos/" . $_FILES["video"]["name"]);
                echo "Stored in: " . "../videos/" . $_FILES["video"]["name"];
            }
        }

    }else{
        echo "Invalid file";
    }

            try {



                //insert into database

                $stmt = $dbconn->prepare('INSERT INTO videos (videotitle,video,editedBy,duration) VALUES (:videoTitle, :video, :editedBy, :duration)') ;

                $stmt->execute(array(

                    ':videoTitle' => $videoTitle,

                    ':video' => $upload,

                    ':editedBy' => "admin",
                    
                    ':duration' => "12"
                

                ));



                //redirect to videos page

                header('Location: index.php');

                exit;



            } catch(PDOException $e) {

                echo $e->getMessage();

            }

}
?>

I have looked at the heroku logs and the errors I am getting are:

PHP Warning: move_uploaded_file(../videos/VID_20201129_223935.mp4): failed to open stream: No such file or directory in /app/users/admin/videoUpload.php on line 53

PHP Warning: move_uploaded_file(): Unable to move '/tmp/phpoLjPU4' to '../videos/VID_20201129_223935.mp4' in /app/users/admin/videoUpload.php on line 53

This is to do with the lines:

// this is line 53
move_uploaded_file($_FILES["video"]["tmp_name"],
    "../videos/" . $_FILES["video"]["name"]); 

I am not sure what would cause this error, is there something I am missing or could it be to do with how I have heroku set up?

As a side note, I have become aware that using extract is not the most secure way to get form data and I am looking to change this.

Thanks

Edit -

This is the form where the information is gathered

<form action='videoUpload.php' method='post' enctype="multipart/form-data">

    <h2>Add Video</h2>  
        <p><label>Title</label><br />

        <input type='text' name='videoTitle' required value='<?php if(isset($error)){ echo $_POST['videoTitle'];}?>'></p>



        <p><label>Video</label><br />

        <input type="file" name='video' id="video" required value='<?php if(isset($error)){ echo $_POST['video'];}?>'></p>

        <p><input type='submit' name='submit' value='Submit'></p>



    </form>
lross12
  • 73
  • 6

1 Answers1

0

In view of the comments I made regarding using the full path I put the following together with the hope that it might help solve your problem ~ though it is untested.

Any fields from the form that submits to this script that is used in the extract method should really be validated and sanitised ( though the prepared statement will help protect the db anyway ) - so by declaring these fields with a suitable filter you can call filter_input or filter_input_array to assist that protection. I usually run checks on the POST array before filtering so that I can deduce if I have omitted fields or have extra - you'll see what I mean below.

In terms of processing the upload if the target folder is not found you need to know about it and act accordingly before trying to save the file or write to the db ( pointless logging an upload that failed perhaps ). chdir returns true if it succeeds in navigating to the target directory so you can fork the logic at that stage to either bailout or create the folder structure ( using mkdir )

<?php
    error_reporting( E_ALL | E_STRICT );
    
    session_start();
    $errors=array();
    $createpath=true;
    
    if( $_SERVER['REQUEST_METHOD']=='POST' ){
    
        try{
            $kb=1024;
            $mb=pow( $kb,2 );
            $maxfs=$mb * 15;    # 15728640 ~ 15Mb   
        

            if( !isset( $_SESSION['loggedin'], $_SESSION['role'] ) or $_SESSION['role'] !== 'admin' ) {
                exit( header( 'Location: ../../index.php' ) );
            }
            
            
            
            if( isset( $_POST['submit'], $_FILES['video'] ) ) {
            
                require_once('../../includes/config.php');
                require_once('../../vendor/autoload.php');
                
                
                /* 
                    To use `extract` in a more secure manner
                */
                
                # create filter rules for form fields with their expected data type
                $args=array(
                    'submit'        =>  FILTER_SANITIZE_STRING,
                    'videoTitle'    => array(   
                                            'filter'    => FILTER_SANITIZE_STRING,
                                            'flags'     => FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH
                                        )
                );
                
                # if there are fields that MUST be submitted
                foreach( array_keys( $args ) as $field ){
                    if( !isset( $_POST[ $field ] ) or empty( $_POST[ $field ] ) ) $errors[]=sprintf('The field "%s" does not appear in the POST array',$field);
                }
                
                # check that no additional POST variables are present
                foreach( $_POST as $field => $value ){
                    if( !in_array( $field, array_keys( $args ) ) ) $errors[]=sprintf('Unknown parameter supplied "%s"',$field);
                }
                
                $_POST=filter_input_array( INPUT_POST, $args );
                extract( $_POST );



                $name=$_FILES['video']['name'];
                $type=$_FILES['video']['type'];
                $size=$_FILES['video']['size'];
                $error=$_FILES['video']['error'];
                $tmp=$_FILES['video']['tmp_name'];
                
                function uploaderror( $error ){ 
                    switch( $error ) { 
                        case UPLOAD_ERR_INI_SIZE: return 'The uploaded file exceeds the upload_max_filesize directive in php.ini'; 
                        case UPLOAD_ERR_FORM_SIZE: return 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form'; 
                        case UPLOAD_ERR_PARTIAL: return 'The uploaded file was only partially uploaded'; 
                        case UPLOAD_ERR_NO_FILE: return 'No file was uploaded'; 
                        case UPLOAD_ERR_NO_TMP_DIR: return 'Missing a temporary folder'; 
                        case UPLOAD_ERR_CANT_WRITE: return 'Failed to write file to disk'; 
                        case UPLOAD_ERR_EXTENSION: return 'File upload stopped by extension'; 
                        default: return 'Unknown error';
                    }
                }
                
                
                $allowedExts = array('ogg', 'mp4', 'wma');
                $types=array('video/mp4','video/ogg','video/wma');
                $extension = pathinfo( $name, PATHINFO_EXTENSION );
                
                
                if( in_array( $type, $types ) && in_array( $extension, $allowedExts ) && $size <= $maxfs ) {
                    if( $error !==UPLOAD_ERR_OK ) {
                        $errors[]=sprintf('Error uploading file: %s',uploaderror( $error ));
                    } else {
                    
                        # get the full path to current working directory
                        $cwd=getcwd();
                        
                        # attempt to traverse directory structure to desired location - up one level and find folder
                        $status=chdir('../videos/');
                        
                        # If the directory does not exist...
                        if( !$status ) {
                            
                            chdir('../');
                            $targetpath=sprintf( '%s/videos/', getcwd() );
                            
                            # Attempt to create THIS path or exit???
                            if( $createpath ){
                                mkdir( $targetpath, 0777, true );
                                chdir( $targetpath );
                            } else exit( sprintf( '<h1>Fatal Error: Target Directory "%s" does not exist!</h1>', $targetpath ) );
                        }
                        
                        # get the fully qualified path of the target directory
                        $target=getcwd();
                        
                        # create the full filepath for uploaded file
                        $targetfile=sprintf('%s/%s',$target,$name);

                        
                        # save the file
                        if( !file_exists( $targetfile ) ){
                            $status=move_uploaded_file( $tmp, $targetfile );
                            if( !$status )$errors[]=sprintf( 'Failed to move file to target directory: %s', $target );
                        }else{
                            $errors[]=sprintf('The file "%s" already exists!',$name);
                        }
                    }
                    
                    
                    
                    
                    
                    
                    
                    
                    if( empty( $dbconn ) )$errors[]='No database connection available';
                    
                    if( empty( $errors ) ){
                    
                        $sql='INSERT INTO `videos` ( `videotitle`, `video`, `editedBy`, `duration` ) VALUES ( :videoTitle, :video, :editedBy, :duration )';
                        try{
                        
                            $stmt=$dbconn->prepare( $sql );
                            $args=array(
                                ':videoTitle'   => $videoTitle,
                                ':video'        => $name,
                                ':editedBy'     => 'admin',
                                ':duration'     => 12
                            );
                            $result=$stmt->execute( $args );
                            if( !$result ) $errors[]='Failed to add record';
                            
                            # redirect if everything went OK
                            if( empty( $errors ) )exit( header( 'Location: index.php' ) );
                            
                            
                        }catch( PDOException $e ){
                            $errors[]=$e->getMessage();
                        }
                    }else{
                        $errors[]='Unwilling to commit to db due to previous errors';
                    }
                }else{
                    $errors[]='File failed testing - incorrect type or too large';
                }
            }else{
                $errors[]='Critical error';
            }
            
            
            # if there were errors, let the user know
            foreach( $errors as $error )printf( '<div>%s</div>', $error );
            
        }catch( Exception $e ){
            exit( 'Bad foo: '.$e->getCode() );
        }
    }
    
    # if page accessed by GET or similar....
    http_response_code(404);
?>
Professor Abronsius
  • 33,063
  • 5
  • 32
  • 46
  • Sorry, just seen this now, Thank you so much for this. I'm guessing it would just need a few tweaks on my part, when I try uploading now I am getting the following: The field "submit" does not appear in the POST array The field "videoTitle" does not appear in the POST array Unknown parameter supplied "videoTitle" Unknown parameter supplied "videoDuration" Unknown parameter supplied "submit" Unwilling to commit to db due to previous errors – lross12 Dec 09 '20 at 12:49
  • In your code you have `isset($_POST["submit"])` so I assumed that it WOULD be available. As for `$videoTitle` ~ I assumed that this was also sent in the FORM submission and automagically created due to `extract` – Professor Abronsius Dec 09 '20 at 17:36
  • I've updated my question to show the form where the data is collected, is it because of this I get those issues? Sorry to bother you again, really appreciate your help with this – lross12 Dec 09 '20 at 18:23