I'm building an app in PHP (Laravel 4 framework) where a teacher in their account can create a digital lesson for a student. Digital lessons can contain the following content:
Raw text entered from forms can obviously be stored in the DB against the lesson_id. All the other content formats will need to be stored somewhere, where I can manage and read the files, as well as keep track of the teachers storage total as I plan to bill for storage thresholds at 5GB, 10GB etc.
On the create a lesson page, content files need to be uploaded as lesson attachments before the lesson is saved, so a teacher can visually see all the lessons content, and then hit save to create the lesson instantly.
Here's what I've come up with:
Upload all lesson file attachments to AWS S3 to the teachers dedicated bucket, before the lesson is created. Add the teachers ID and date time to each filename.
Force all uploaded video / audio files to be converted to .mp4, .mp3, etc. if they are not in an iDevice friendly format or they exceed a file size limit. Use FFmpeg to do this.
When the lesson is saved and created, record the S3 file URL's against the lesson ID in the DB.
If the lesson has not been created after a specific period of time, run a cron job to check for uploaded S3 files with no lesson and delete them.
I am unsure what is the best way to solve this problem as user uploaded content management is really new to me.
What do you think of this approach? Can you recommend an improved or better way to solve this problem?
<?php
// Set the max file size and upload path
$maxFileSize = (100 * 1024);
$uploadDir = 'upload/';
// Do not edit these values
$showForm = false;
$formError = false;
$uploadFilePath = '';
if (isset($_POST['submit'])) {
// Check for upload errors
if ($_FILES['file']['error'] > 0) {
$formError = 'Error: ' . $_FILES['file']['error'];
} else {
$fileName = $_FILES['file']['name'] ; // the name of the uploaded file
$fileType = $_FILES['file']['type'] ; // the type of the uploaded file
$fileSize = $_FILES['file']['size'] ; // the size in bytes of the uploaded file
$tempLocation = $_FILES['file']['tmp_name']; // the temp file location
// Check the file type
if ( ! in_array($fileType, array('image/jpeg', 'image/png'))) {
$formError = 'Invalid file type. Must be jpeg or png.';
}
// Check the file size
elseif ($fileSize > $maxFileSize || $fileSize < 0) {
$formError = 'Invalid file size. Must be between 1 and ' . $maxFileSize . ' kb.';
}
// Make sure the file does not exist
elseif (file_exists($uploadDir . $fileName)) {
$formError = 'The file "' . $fileName . '" already exists.';
}
// The file is valid so continue with the upload
else {
// Move the file from the tmp dir to the desired location
move_uploaded_file($tempLocation, $uploadDir . $fileName);
// Remember the complete upload file path
$uploadFilePath = $uploadDir . $fileName;
// Store the upload information in the database
$c = mysql_connect('localhost','root','') or die (mysql_error());
$d = mysql_select_db('datebase_name') or die(mysql_error());
mysql_query("insert into table_name values('','$fileName','$fileType','$fileSize')") or die(mysql_error());
}
}
} else {
$showForm = true;
}
?>
<!DOCTYPE html>
<html>
<head>
<title>Hello!</title>
</head>
<body>
<?php
if ($showForm) {
if ($formError !== false) {
echo '<p>' . $formError . '</p>';
}
?>
<form action="upload.php" method="post" enctype="multipart/form-data">
<label for="file">Filename:</label>
<input type="file" name="file" id="file"><br>
<input type="submit" name="submit" value="Submit"><br>
</form>
<?php
} else {
echo '<p>File stored at: ' . $uploadFilePath . '</p>';
}
?>
</body>
</html>
Here the file will be stored in the folder named "upload" and the uploaded file size and type are saved in the database.
In the example above, the database table has 4 columns (in this order): id, file name, file type and file size.
Note: This is a basic example. Do not forget to improve the file validation to enhance security. It would also be better to not show users the upload location. An upload confirmation like "File uploaded successfully" will suffice in most cases.
Short answer - your suggested approach is fine.
Long answer...
I have a similar situation where I allow users to upload images of items they are advertising for sale. While I wont have as many files as you, nor the complexity of many different file types, the principle is the same...
In my form that enables users to create an advert (lesson in your case) I use a dropzone (dropzone.js) which users can drag and drop images. This prompts an AJAX post call to my Laravel API and the files are uploaded immediately (i.e. before the 'Submit' button has been pressed). They upload to a tmp directory. The location of this tmp directory is then returned to the browser and a .js script stores the location in a hidden field in my form. When the user is happy, he hits submit and the form is uploaded. At this point, I handle the form and (amongst other things) resize the images and move them to their permanent location and the path is stored in the database. The tmp directory is then deleted.
I then run a cron job on once a day to clear any tmp directories which still exist (which will arise from users dropping in images, but then not submitting the form).
I think your logic is fine, I thought it might help you to hear how someone else tackled the workflow.
Good luck