multiple image upload

teroristd

Registered
Здравейте, първо ще обясня какво се опитвам да постигна, след това ще постна кода който имам до момента. Искам да направя multiple image upload форма, само с едно поле за качване на снимките, по възможност без джаваскрипт. Идеята ми е да има един бутон освен субмита, който като се натисне да пълни някакъв масив примерно и като се субмитне формата да се качат снимките в базата с едно id. В смисъл на едно и също id да отговарят няколко снимки. Ето пример какво очаквам да имам в базата.

| id | image | title | category | text |
-----------------------------------------------------------
| 1 | asd_1.jpg asd_2.jpg | text | text | text |

В момента се качва само по една снимка. Ето и кода който имам.

Това е модела
Код:
class UploadModel
{
    private $_config;
    private $_database;

    public function __construct(Config $config, Database $database)
    {
        $this->_config = $config;

        $this->_database = $database;
    }

    public function run($title, $category, $text, $add_more)
    {
        $img_name = count($_FILES['image']['name']);

        for ($i = 0; $i < $img_name; $i++)
        {
            $imageFolderPath = realpath('..\uploads') . DIRECTORY_SEPARATOR;
            $fileTmpLoc = $_FILES['image']['tmp_name'][$i];
            $fileName = $_FILES['image']['name'][$i];
            $clasicMimeType = $_FILES['image']['type'][$i];

            $exp = explode('.', $fileName);
            $end = strtolower(end($exp));
            $newFileName = bin2hex(openssl_random_pseudo_bytes(16)) . '.' . $end;

            if ($fileTmpLoc == null)
            {
                throw new \Exception('empty', 405);
            }
            else
            {
                if ($clasicMimeType !== 'image/jpg' && $clasicMimeType !== 'image/jpeg')
                {
                    throw new \Exception('mimeType', 405);
                }

                $finfo = new \finfo(FILEINFO_MIME_TYPE);
                $mimeType = $finfo->file($fileTmpLoc);

                if ($mimeType !== 'image/jpg' && $mimeType !== 'image/jpeg')
                {
                    throw new \Exception('mimeType', 405);
                }

                if ($end !== 'jpg' && $end !== 'jpeg')
                {
                    throw new \Exception('mimeType', 405);
                }

                if ($add_more)
                {
                    throw new \Exception('add_more', 405);
                }

                if (empty($title))
                {
                    throw new \Exception('empty', 405);
                }

                if (empty($category))
                {
                    throw new \Exception('empty', 405);
                }

                if (empty($text))
                {
                    throw new \Exception('empty', 405);
                }

                move_uploaded_file($fileTmpLoc, $imageFolderPath . $newFileName);

                $text = nl2br($text);

                $this->_database->prepare('INSERT INTO images (image,title,category,text) VALUES(?,?,?,?)', array($newFileName, $title, $category, $text))->execute();

                throw new \Exception('ok', 200);
            }
        }
    }

Това е контролера
Код:
class Upload
{
    private $_view;
    private $_uploadModel;
    private $_normalize;

    public function __construct(View $view, UploadModel $uploadModel, Normalize $normalize)
    {
        $this->_view = $view;

        $this->_uploadModel = $uploadModel;

        $this->_normalize = $normalize;
    }

    public function run()
    {
        $submit = $this->_normalize->post('submit', 'trim');

        $title = $this->_normalize->post('title', 'trim');

        $category = $this->_normalize->post('category', 'trim');

        $text = $this->_normalize->post('text', 'trim');

        $add_more = $this->_normalize->post('add_more', 'trim');

        try
        {
            $this->_uploadModel->run($title, $category, $text, $add_more);
        }
        catch (\Throwable $exc)
        {

            if (isset($add_more))
            {
                if ($exc->getMessage() == 'add_more')
                {
                    $this->_view->_message = 'message_1';

                    $this->layout();
                }
            }

            if (isset($submit))
            {
                if ($exc->getMessage() == 'ok')
                {
                    $this->_view->_message = 'message_2';

                    $this->layout();
                }
                elseif ($exc->getMessage() == 'empty')
                {
                    $this->_view->_message = 'message_3';

                    $this->layout();
                }
                elseif ($exc->getMessage() == 'mimeType')
                {
                    $this->_view->_message = 'message_4';

                    $this->layout();
                }
            }
            else
            {
                $this->_view->_message = 'message_0';

                $this->layout();
            }
        }
    }

    private function layout()
    {
        $this->_view->display('header');
        $this->_view->display('body_upload');
        $this->_view->display('footer');
    }
}

Това е вю-то
Код:
<body>

<div class="container">

    <form method="post" enctype="multipart/form-data">

        <input type="file" name="image[]" multiple="true"/>

        <input type="submit" name="add_more" value="Add More Images"/>

        <p>Заглавие</p>
        <input type="text" name="title"/>

        <p>Категория</p>
        <select name="category">
            <option disabled selected value> ---</option>
            <option value="асд">асд</option>
        </select>

        <p>Текст</p>
        <textarea name="text" rows="5" cols="30" wrap="hard">
        </textarea>

        <br><br>
        <input type="submit" name="submit"/>

    </form>

    <div class="messages">
        <p><?php echo $this->_message; ?></p>
    </div>

</div>

<script>
    $(document).ready(function () {
        $(".messages").animate({opacity: 0}, 0);
        $(".messages").animate({opacity: 1}, 500);
    });
</script>

</body>
 
Ами защото ид-то ти е уникално и ти дава грешка, че вече не можеш да добавяш запис с такова ид. Идеята е да конкатенираш имената на файловете във for цикъла и тогава да направиш един insert, но проблемът е, че не се прави така. Прочети за нормализация на базата данни.
 
В смисъл аз не се опитвам да добавям едно и също id, то ми е auto increment. Целта ми е в един ред да влезнат няколко имена на снимки, които после с едно explode да си ги извадя, но в случая в базата влиза само едно име, а също и една снимка се качва в папката.

Предполагам това е грешен начин, но sql-ите не са ми сила и гледам да избягвам разните join-ове и други подобни :) .
 
Създай си един масив преди for цикъла. След това за всеки елемент от цикъла вкарвай в масива $newFileName. Извади си заявката от цикъла и използвай функцията implode() за да преобразуваш масива в низ. Така го виждам аз:
PHP:
$images = array();

for ($i = 0; $i < $img_name; $i++) {
	
	// ...
	
	$images[] = $newFileName;
	
}

$this->_database->prepare('INSERT INTO images (image,title,category,text) VALUES(?,?,?,?)', array(implode(' ', $images), $title, $category, $text))->execute(); 

throw new \Exception('ok', 200);

Това би трябвало да ти свърши работа, макар, че правилният начин ти го каза @lam3r4370.
 
Сигурно не завърташ правилно цикъла. Я принтни $img_name или направо дъмпни $_FILES ( var_dump($_FILES) )
 
array(1) { ["image"]=> array(5) { ["name"]=> array(1) { [0]=> string(10) "allens.jpg" } ["type"]=> array(1) { [0]=> string(10) "image/jpeg" } ["tmp_name"]=> array(1) { [0]=> string(24) "C:\xampp\tmp\php8DCC.tmp" } ["error"]=> array(1) { [0]=> int(0) } ["size"]=> array(1) { [0]=> int(42569) } } }
 
Това при повече от 1 избран файл ли ти го дава ?
Според мен имаш грешка и при проверката за разширението на файловете. Използваш логическо "и" вместо логическо "или"
 
Добре, нека оставим моите опити за грешна имплементация :) и да се съсредоточим върху правилния вариант. Ще помоля само за по-описателно решение. Как трябва да изглеждат таблиците? Какви заявки трябват за да вкарвам и да вадя? В крайна сметка трябва да се получи нещо като галерия. Към едно id няколко снимки, като първата ще е главната, заглавие, текст и т.н.
 
Какво имаш като таблици - ако имаш нещо тип новини или някъде, където искаш да прикачиш всичките снимки си остави тази ти таблица така с по едно изображение на id и направи свързваща таблица news_images и там записваш съответно ид на новина и ид на снимка
 
Това е таблицата която имам, примерно news. Id-то ми е аутоинкримент.

Таблица news

| id | image | title | category | text |

Втората таблица примерно news_images така ли трябва да изглежда, като в полето image_id да записвам id-то на news?

Таблица news_images

| id | image_id | image|

Междувременно ми изникна един въпрос. Как трябва да взема id-то на news при положение че имам една форма?
 
Да кажем, че си схванал идеята, но нека image_id от таблицата news_images да бъде news_id (по-разбираемо е). Това поле ще ти е връзката с таблицата news. Ето примерни таблици със съответна информация в тях:

- таблица news

id | image | title
1 | as13d.jpg | нещо си
2 | aasca.jpg | бла бла
3 | eaeas.jpg | друго

- таблица news_images

id | news_id | image
1 | 1 | img1.jpg
2 | 1 | img2.jpg
3 | 1 | img3.jpg
4 | 2 | img1.jpg

Как трябва да взема id-то на news при положение че имам една форма?

Ако искаш едновременно с добавянето на новина да добавяш и изображения можеш да използваш http://php.net/manual/en/pdo.lastinsertid.php
 
flafy каза:
Как трябва да взема id-то на news при положение че имам една форма?

Ако искаш едновременно с добавянето на новина да добавяш и изображения можеш да използваш http://php.net/manual/en/pdo.lastinsertid.php

lastinsertid го има само след като е качена първата таблица което е проблем.
 
1. вкарваш новината в news
2. взимаш last_insert_id
3. вкарваш снимките с news_id = от точка 2.
 
Така е при идеалния вариант. Обаче ако някой почне от снимките например или при back, refresh и т.н. се получават бъгове. Също така ако се опитам да го ползвам в друг файл го губя.
 
След POST заявка е хубаво да правиш redirect към някоя страница, именно за да ги няма тия "бъгове" (resubmit на формата, ако това имаш предвид).
А какво имаш предвид под друг файл?
 
Точно тук е проблема. Нали трябва да субмитна първо текстовете за да имам last insert id, а ако редиректна губя стойността.
 
teroristd каза:
Точно тук е проблема. Нали трябва да субмитна първо текстовете за да имам last insert id, а ако редиректна губя стойността.

Тия 3 точки, които написах, стават когато добавяш новината. Редиректа е когато направиш всичко (добавиш новината, снимките).

Ако пък добавяш снимките после (отделно), то направи редирект към /add-photos/$id или нещо такова.
 

Горе