somebody can help me to make file uploading in form with another data like name email etc... https://github.com/psytonik/School-Project-PHP/tree/master/school_project this is project
            Asked
            
        
        
            Active
            
        
            Viewed 3,298 times
        
    -5
            
            
        - 
                    Please put the code that is not working to your expectations in your question. – jrswgtr Aug 18 '18 at 16:57
- 
                    problem that i don't know how to do the file uploading if that external function or inside create function – Anthony Fink Aug 18 '18 at 17:01
- 
                    look into this: https://www.w3schools.com/php/php_file_upload.asp then create a controller endpoint for your form submission. – jrswgtr Aug 18 '18 at 17:04
- 
                    i saw this but i do project in mvc style – Anthony Fink Aug 18 '18 at 17:07
- 
                    Yes, you should create a controller endpoint to display and handle your form. Use the code from W3schools in your controller function. – jrswgtr Aug 18 '18 at 17:08
- 
                    ok what i do after controller ? – Anthony Fink Aug 18 '18 at 17:22
- 
                    You should create a view file with the form html. In the controller function you render the view. Create a check in the controller function to see if the form is submitted. (something like `if ( isset($_POST['file']) )` ) Then do the actual file upload. – jrswgtr Aug 18 '18 at 17:23
- 
                    check please my github to understand structure of my mvc – Anthony Fink Aug 18 '18 at 17:26
- 
                    I'm sorry but you can't expect us to read into an entire project repository. Please read this: https://stackoverflow.com/help/how-to-ask and adjust your question to something more concrete. – jrswgtr Aug 18 '18 at 17:31
- 
                    Notice: Undefined index: fileToUpload in /Applications/XAMPP/xamppfiles/htdocs/school_project/app/controllers/Uploads.php on line 15 Notice: Undefined index: fileToUpload in /Applications/XAMPP/xamppfiles/htdocs/school_project/app/controllers/Uploads.php on line 35 Sorry, only JPG, JPEG, PNG & GIF files are allowed.Sorry, your file was not uploaded. – Anthony Fink Aug 18 '18 at 17:40
1 Answers
2
            Based on your app structure I prepared some code which submits a form and uploads multiple files. It should give you an idea of the workflow.
As a note, you should take advantage of:
- the Composer autoloader;
- a dependency injection container, like PHP-DI;
- a router, like FastRoute;
- an implementation of "PSR-7: HTTP message interfaces" (which abstracts the uploaded files list too), like Zend-Diactoros.
Some resources:
- MVC for advanced PHP developers;
- How should a model be structured in MVC;
- Understanding MVC Views in PHP
- Error reporting basics
- PHP Standards Recommendations (1, 2, 4, 7 and 11).
- Tom Butler's programming blog
- Catalog of Patterns of Enterprise Application Architecture
Some series:
A)
- Building a Domain Model - An Introduction to Persistence Agnosticism
- Building a Domain Model – Integrating Data Mappers
- An Introduction to Services
- Handling Collections of Aggregate Roots – the Repository Pattern
B)
- An Introduction to the Front Controller Pattern, Part 1
- An Introduction to the Front Controller Pattern, Part 2
controllers/Test.php
Accessible through the route: http://[your-host]/test
<?php
class Test extends Controller {
    private $uploader;
    public function __construct() {
        $this->uploader = new Uploader();
    }
    public function index($extra = []) {
        $data = array_merge([], $extra);
        $this->view('test/index', $data);
    }
    public function upload() {
        $data = [];
        // Get the test name.
        $testName = $_POST['test_name'] ?? '';
        // Validate the test name.
        if (empty($testName)) {
            $errors['test_name'] = 'Please enter student name';
        }
        // Check the files list.
        try {
            if (!$_FILES) {
                throw new UnexpectedValueException(
                'There was a problem with the upload. Please try again.'
                );
            }
        } catch (Exception $exc) {
            echo $exc->getMessage();
            exit();
        }
        // If no errors, then upload the files.
        if (empty($errors)) {
            $uploadResult = $this->uploader->upload($_FILES['files']);
            if ($uploadResult !== TRUE) {
                $errors['files'] = $uploadResult;
            }
        }
        $data['test_name'] = $testName;
        $data['errors'] = $errors ?? [];
        // Flash some success message using the flash() function if no errors occurred...
        $this->index($data);
    }
}
libraries/Uploader.php
You could/should split it into more methods.
<?php
class Uploader {
    /**
     * If the value is set to a relative path, then the given path is
     * relative to the document root, e.g. to the "public" directory.
     */
    const UPLOAD_DIR = APPROOT . '/uploads/' /* This is an absolute path */;
    const UPLOAD_DIR_ACCESS_MODE = 0777;
    const UPLOAD_MAX_FILE_SIZE = 10485760;
    const UPLOAD_ALLOWED_MIME_TYPES = [
        'image/jpeg',
        'image/png',
        'image/gif',
    ];
    /**
     *
     */
    public function __construct() {
    }
    /**
     * Upload the files list.
     *
     * @param array $files (optional) Files list - as received from $_FILES variable.
     * @return bool|string[] TRUE on success, or a list of errors on failure.
     */
    public function upload(array $files = []) {
        // Normalize the files list.
        $normalizedFiles = $this->normalizeFiles($files);
        // Upload each file.
        foreach ($normalizedFiles as $normalizedFile) {
            $uploadResult = $this->uploadFile($normalizedFile);
            if ($uploadResult !== TRUE) {
                $errors[] = $uploadResult;
            }
        }
        // Return TRUE on success, or the errors list on failure.
        return empty($errors) ? TRUE : $errors;
    }
    /**
     * Normalize the files list.
     *
     * @link https://www.php-fig.org/psr/psr-7/#16-uploaded-files PSR-7: 1.6 Uploaded files.
     *
     * @param array $files (optional) Files list - as received from $_FILES variable.
     * @return array Normalized files list.
     */
    private function normalizeFiles(array $files = []) {
        $normalizedFiles = [];
        foreach ($files as $filesKey => $filesItem) {
            foreach ($filesItem as $itemKey => $itemValue) {
                $normalizedFiles[$itemKey][$filesKey] = $itemValue;
            }
        }
        return $normalizedFiles;
    }
    /**
     * Upload a file.
     *
     * @param array $file A normalized file item - as received from $_FILES variable.
     * @return bool|string TRUE on success, or an error string on failure.
     */
    private function uploadFile(array $file = []) {
        $name = $file['name'];
        $type = $file['type'];
        $tmpName = $file['tmp_name'];
        $error = $file['error'];
        $size = $file['size'];
        /*
         * Validate the file error. The actual upload takes place when the file
         * error is UPLOAD_ERR_OK (the first case in this switch statement).
         *
         * @link https://secure.php.net/manual/en/features.file-upload.errors.php Error Messages Explained.
         */
        switch ($error) {
            case UPLOAD_ERR_OK: /* There is no error, the file can be uploaded. */
                // Validate the file size.
                if ($size > self::UPLOAD_MAX_FILE_SIZE) {
                    return sprintf('The size of the file "%s" exceeds the maximal allowed size (%s Byte).'
                            , $name
                            , self::UPLOAD_MAX_FILE_SIZE
                    );
                }
                // Validate the file type.
                if (!in_array($type, self::UPLOAD_ALLOWED_MIME_TYPES)) {
                    return sprintf('The file "%s" is not of a valid MIME type. Allowed MIME types: %s.'
                            , $name
                            , implode(', ', self::UPLOAD_ALLOWED_MIME_TYPES)
                    );
                }
                // Define the upload path.
                $uploadDirPath = rtrim(self::UPLOAD_DIR, '/');
                $uploadPath = $uploadDirPath . '/' . $name;
                // Create the upload directory.
                $this->createDirectory($uploadDirPath);
                // Move the file to the new location.
                if (!move_uploaded_file($tmpName, $uploadPath)) {
                    return sprintf('The file "%s" could not be moved to the specified location.'
                            , $name
                    );
                }
                return TRUE;
                break;
            case UPLOAD_ERR_INI_SIZE:
            case UPLOAD_ERR_FORM_SIZE:
                return sprintf('The provided file "%s" exceeds the allowed file size.'
                        , $name
                );
                break;
            case UPLOAD_ERR_PARTIAL:
                return sprintf('The provided file "%s" was only partially uploaded.'
                        , $name
                );
                break;
            case UPLOAD_ERR_NO_FILE:
                return 'No file provided. Please select at least one file.';
                break;
            //...
            // AND SO ON FOR THE OTHER FILE ERROR TYPES...
            //...
            default:
                return 'There was a problem with the upload. Please try again.';
                break;
        }
        return TRUE;
    }
    /**
     * Create a directory at the specified path.
     *
     * @param string $path Directory path.
     * @return $this
     */
    private function createDirectory(string $path) {
        try {
            if (file_exists($path) && !is_dir($path)) {
                throw new UnexpectedValueException(
                'The upload directory can not be created because '
                . 'a file having the same name already exists!'
                );
            }
        } catch (Exception $exc) {
            echo $exc->getMessage();
            exit();
        }
        if (!is_dir($path)) {
            mkdir($path, self::UPLOAD_DIR_ACCESS_MODE, TRUE);
        }
        return $this;
    }
}
views/test/index.php
Note the form action: http://[your-host]/test/upload. It points to the Test controller and the upload method. Well, I named the method upload, to point that it's about a test regarding the upload process. Though I should have named it save, or similar, to mirror the fact, that some data is to be saved, including the uploaded files.
<?php require APPROOT . '/views/inc/header.php'; ?>
<div class="container">
    <div class="row">
        <div class="sm-12 col">
            <h2>Test upload</h2>
            <p>Submit the form</p>
            <form action="<?php echo URLROOT; ?>/test/upload" method="post" enctype="multipart/form-data">
                <div class="form-group">
                    <label for="test_name">Test name <sup>*</sup></label>
                    <input type="text" id="test_name" name="test_name" class="form-control form-control-lg <?php echo empty($data['errors']['test_name']) ? '' : 'is-invalid'; ?>" value="<?php echo $data['test_name'] ?? ''; ?>" />
                    <span class="invalid-feedback"><?php echo $data['errors']['test_name'] ?? ''; ?></span>
                </div>
                <div class="form-group">
                    <label for="myFiles">Files <sup>*</sup></label></label>
                    <input type="file" id="myFiles" name="files[]" multiple class="form-control form-control-lg <?php echo empty($data['errors']['files']) ? '' : 'is-invalid'; ?>" />
                    <span class="invalid-feedback"><?php echo empty($data['errors']['files']) ? '' : implode('<br/>', $data['errors']['files']); ?></span>
                </div>
                <input type="submit" value="Submit" class="btn btn-success">
            </form>
        </div>
    </div>
</div>
<?php require APPROOT . '/views/inc/footer.php'; ?>
 
    
    
        PajuranCodes
        
- 303
- 3
- 12
- 43
- 
                    For the users who will, maybe, decide to downvote my answer: Be fair and let me know the motives of your downvote, so that I can change my answer correspondingly. I am open to any suggestions or critiques. Thanks. – PajuranCodes Aug 19 '18 at 08:29
- 
                    @AnthonyFink Hi, I remembered about some additional resources. So I extended the list in my answer. Read the series in the given order. Good luck. – PajuranCodes Aug 19 '18 at 12:06
- 
                    I upvoted your answer. But I think the question, which is very low effort, is not worthy of your very extensive answer. – jrswgtr Aug 19 '18 at 21:34
- 
                    Thank you, @jrswgtr. Maybe, in other situations, I would have thought in a similar way. But, this time, I really appreciated the whole effort that Anthony put in his project. – PajuranCodes Aug 19 '18 at 22:17
- 
                    I'm new to php and just learn. maybe i don't really know how to properly ask the question, but everyday you learn something new. i wish there were more people like @dakis, they really help to people like me. – Anthony Fink Aug 20 '18 at 00:28
- 
                    @jrswgtr i can't put there all the structure of my php, maybe it's a bit different from another mvc structures out there. – Anthony Fink Aug 20 '18 at 00:28
- 
                    @AnthonyFink Indeed, Anthony, learning is the key. Take a look at [this](https://stackoverflow.com/questions/51729687/whats-the-best-approach-to-divide-model-and-actions-into-classes-in-mvc-pattern/51735316#51735316) and [this](https://stackoverflow.com/questions/51436961/mvc-is-this-the-correct-sequence-to-initialize-invoke-mvc-layers/51450648#51450648) too. Maybe tey'll be of any help to you. – PajuranCodes Aug 20 '18 at 11:07
