Использование PHP для загрузки изображений в папку при сохранении описания в базе данных - PullRequest
1 голос
/ 14 июля 2011

Пользователь решает загрузить несколько изображений для своего классифицированного списка. Что мне нужно, чтобы это произошло:

  1. Загрузка изображений с описаниями для каждого из изображений - решено
  2. Сохранить изображения в указанной папке
  3. Сохранить местоположение изображения в моей базе данных MySQL с описаниями - решено
  4. Уметь называть изображения и описания в их классифицированных списках в виде настроек галереи

Моя схема таблицы настроена так (упрощенно):

ad_id | member_id | category | subcategory | ... | photo_0_href | photo_0_desc ... | etc.

Может ли кто-нибудь провести меня через этот процесс? Спасибо.

step3.php

<form action="upload.php" method="post" enctype="multipart/form-data">
<p>
<label for="file0">Filename: </label>
<input name="file[]" type="file" id="file0" size="20" />
</p>
<p>
<label for="file0desc">Description: </label>
<textarea rows="10" cols="30" id="file0desc" class="textarea"></textarea>
</p>
<p>
<label for="file1">Filename: </label>
<input name="file[]" type="file" id="file1" size="20" />
</p>
<p>
<label for="file1desc">Description: </label>
<textarea rows="10" cols="30" id="file1desc" class="textarea"></textarea>
</p>
<p>
<input id="submit" type="submit" name="submit" value="Continue to Step 4" />
</p>
</form>

upload.php

<?php

if ((($_FILES["file"]["type"] == "image/gif")
|| ($_FILES["file"]["type"] == "image/jpeg")
|| ($_FILES["file"]["type"] == "image/pjpeg")
|| ($_FILES["file"]["type"] == "image/png"))
&& ($_FILES["file"]["size"] < 1048600)) // less than 1MB
  {
  if ($_FILES["file"]["error"] > 0)
    {
    echo "Return Code: " . $_FILES["file"]["error"] . "<br />";
    }
  else
    {
    header("Location: step4.php");
/*
    echo "Upload: " . $_FILES["file"]["name"] . "<br />";
    echo "Type: " . $_FILES["file"]["type"] . "<br />";
    echo "Size: " . ($_FILES["file"]["size"] / 1024) . " Kb<br />";
    echo "Temp file: " . $_FILES["file"]["tmp_name"] . "<br />";

*/
    if (file_exists("upload/" . $_FILES["file"]["name"]))
      {
      echo $_FILES["file"]["name"] . " already exists. ";
      }
    else
      {
      move_uploaded_file($_FILES["file"]["tmp_name"],
      "upload/" . $_FILES["file"]["name"]);
      echo "Stored in: " . "upload/" . $_FILES["file"]["name"];
      }
    }
  }
else
  {
  echo "Invalid file";
  }
?>

Я знаю, что мой upload.php еще не настроен для нескольких файлов изображений, но это только начало.

Я решил сохранить описания в базе данных, используя $_SESSION['file_n_desc']. Мне просто нужно выяснить, как загрузить штопанные изображения в папку, а затем сохранить местоположения в базе данных.

Мне также нужно переименовать изображение в случайную строку (чтобы предотвратить перезапись изображений). Я знаю, что могу сделать это с помощью функции rand().

Ответы [ 3 ]

2 голосов
/ 15 июля 2011

1) Загрузка файлов

При использовании синтаксиса массива для ввода файлов индекс файла является последним ключом.$_FILES["file"]["name"], например, это массив имен файлов.Чтобы получить информацию для i-го файла, вам необходимо получить доступ к $_FILES["file"]["name"][$i], $_FILES["file"]["size"][$i] и т.

2) Сохранение изображений в папку

Некоторые данные в$_FILES (например, имя) исходит от клиента и, следовательно, ему нельзя доверять (то есть сначала проверять).В случае имя файла , вы можете начать с использования realpath, чтобы убедиться, что путь к целевому файлу безопасен, или использовать basename или pathinfo для извлечения последнего компонента предоставленного имени перед сборкой целевого пути.

3) Сохранение информации об изображении в БД

(Неполная) схема базы данных, которую вы даетеПохоже, вы даете каждому изображению два столбца в одной таблице.В реляционной модели отношения «многие ко» моделируются отдельной таблицей:

CREATE TABLE images (
    id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
    `path` VARCHAR(256) NOT NULL,
    `description` TEXT,
    `member` INT UNSIGNED NOT NULL,
    FOREIGN KEY `member` REFERENCES members (`id`) ON DELETE CASCADE ON UPDATE CASCADE -- the image's owner
) Engine=InnoDB;

-- Note: this is a many-to-many relationship
CREATE TABLE ad_images (
    `ad` INT UNSIGNED NOT NULL,
    `image` INT UNSIGNED NOT NULL,
    FOREIGN KEY `ad` REFERENCES ads (`ad_id`) ON DELETE CASCADE ON UPDATE CASCADE,
    FOREIGN KEY `image` REFERENCES images (id) ON DELETE CASCADE ON UPDATE CASCADE,
    UNIQUE KEY (`ad`, `image`)
) Engine=InnoDB;

В противном случае вы нарушаете правило zero-one-infinity и тратите пространство, когда естьменьше максимального количества изображений.

Другое

Обратите внимание, что вы можете использовать синтаксис массива для полей описания файла, чтобы упростить их обработку.Назовите их «filedesc []».

Вместо длинной последовательности сравнений используйте поиск по массиву или сопоставление с образцом.

function isImage($type) {
    static $imageTypes = array(
            'image/gif'=>1, 'image/jpeg'=>1, 'image/pjpeg'=>1, 'image/png'=>1,
        );
    return isset($imageTypes[$type]);
    /* OR */
    return preg_match('%^image/(?:p?jpeg|gif|png)%', $type);
    /* OR allow all images */
    return preg_match('%^image/%', $type);
}

if (isImage($_FILES["file"]["type"][$idx]) && ($_FILES["file"]["size"][$idx] < 1048600)) {

Тип файла - один из тех, которые предоставляются клиентомценности.Безопаснее было бы использовать fileinfo для получения типа изображения.

$finfo = finfo_open(FILEINFO_MIME_TYPE);

if (isImage(finfo_file($finfo, $path)) && ($_FILES["file"]["size"][$idx] < 1048600)) {

Даже это можно обмануть, если файл имеет действительный заголовок изображения, но остальная часть недопустима.Вы можете использовать библиотеку изображений (например, GD или ImageMagick), чтобы проверить файл, проверив, можете ли вы успешно открыть файл как изображение.

1 голос
/ 15 июля 2011

P.S .: У меня такое ощущение, что вы новичок, и я думаю, что сделал хороший список на PHP Newbies: Как написать хороший код

2) Сохранить изображения в указанную папку

move-uploaded-file должно работать. На ум приходит то, что вы не установили правильные права на запись для перемещения файлов. Какой тип сервера вы используете (Linux / Windows / MacOSX)? Что функция возвращает как логическое (результат)?

Еще одна вещь: мне нужно переименовать изображение в случайную строку (для предотвращения перезаписи изображений). Я знаю, что могу сделать это с Функция rand (), но я забыл упомянуть об этом в своем оригинальном сообщении.

rand() не является случайным и может дать повторяющиеся имена файлов. uniqid будет уникальным

Редактировать: я решил сохранить описания в базе данных, используя $ _SESSION [ 'file_n_desc']. Мне просто нужно выяснить, как загрузить штопать вещи и затем сохранить местоположения в базе данных.

При использовании сеанса, когда вы не переопределяете сеанс, вы используете не базу данных MySQL, а файловую систему . Вы можете прочитать это руководство для сеанса хранения в базе данных . Стандартно этот сеанс очищается при закрытии браузера (только для этого сеанса). Просто попробуйте этот код:

<?php

session_start();

echo "<p>";
if (isset($_SESSION['count'])) {
    echo $_SESSION['count']++;
} else {
    $_SESSION['count'] = 0;
    echo $_SESSION['count']++;
}
echo "</p>";

echo "<p>" . session_id() . "</p>";

Загрузите эту страницу пару раз, не закрывая браузер. Вы получите что-то похожее на:

0

rlu10shi6l390il130qinlt913


1

rlu10shi6l390il130qinlt913

Но когда вы закрываете браузер, идентификатор сеанса изменился, а ваш счетчик обнулился, и вы получили вывод, похожий на.

0

fiakdijmmk38i40f39fm8u5mi4

1

fiakdijmmk38i40f39fm8u5mi4

Уметь называть изображения и описания в своих классифицированных перечисление в виде настройки галереи

Я использовал PDO (Good Read) для выполнения (My) SQL. Я провел юнит-тестирование (TDD), используя phpunit . Для доступа к базе данных я использовал SQLite в режиме памяти (очень приятно проводить SQL-тестирование) => new PDO('sqlite::memory:');. Я пытался следовать трем правилам дяди Боба (Good Read).

Обычно вы разделяете это на несколько файлов. Каждый класс в отдельном файле. Каждый класс должен быть протестирован в Isolation (слабая связь) в отдельном файле.

Я использовал внешний ключ , чтобы отобразить «Листинг к изображению». Я думаю, этот пример проверен довольно тщательно, но сейчас мне пора немного поспать, поэтому я не уверен;).

<?php

function createDatabase() {
    $db = new PDO('sqlite::memory:');
    $db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
    $db->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
    $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    return $db;
}

function createTables($db) {

// Listing table containing all listings.
    $db->exec(
<<<EOT
CREATE TABLE IF NOT EXISTS listing(
id INTEGER PRIMARY KEY, 
description TEXT NOT NULL UNIQUE)
EOT
    );

// Image table containg all images.
    $db->exec(
<<<EOT
CREATE TABLE IF NOT EXISTS image(
id INTEGER PRIMARY KEY, 
listing_id INTEGER,
URL TEXT NOT NULL UNIQUE,
description TEXT NOT NULL UNIQUE,
FOREIGN KEY (listing_id) REFERENCES listing(id))
EOT
    );
}

class Listing {
    private $db;
    private $id;
    public $description;

    /*private function __construct() {

    }*/

    private function __construct(PDO $db, $id, $description) {
        $this->db = $db;
        $this->id = $id;
        $this->description = $description;
    }

    public static function create(PDO $db, $description) {
        $stmt = $db->prepare(<<<EOT
INSERT OR IGNORE INTO listing(description)
VALUES (:description)
EOT
        );
        $stmt->execute(array(
            ":description" => $description
        ));

        if ($stmt->rowCount() !== 1) {
            return NULL;
        }

        return new Listing($db, $db->lastInsertId(), $description);
    }

    public static function get(PDO $db, $id) {
        $stmt       = $db->prepare("SELECT description FROM listing WHERE id = :id");
        $stmt->execute(array(
            ":id" => $id
        ));
        $row = $stmt->fetch();

        if ($row == null) {
            return null;
        }
        return new Listing($db, $id, $row['description']);
    }

    public function getImages() {
        return Image::getImages($this->db, $this);
    }

    public function save() {
            $stmt = $this->db->prepare(
<<<EOT
UPDATE listing SET description = :description WHERE id = :id
EOT
            );
            $stmt->execute(array(
                ":description"  => $this->description,
                ":id"           => $this->id
            ));
    }

    public function id() {
        return $this->id;
    }
}

class Image {
    private $pdo;
    public $URL;
    private $id;
    public $description;

    private function __construct(PDO $pdo, $URL, $description, Listing $listing, $id) {
        $this->pdo          = $pdo;
        $this->URL          = $URL;
        $this->description  = $description;
        $this->id           = $id;
    }

    public static function create(PDO $pdo, $URL, $description, Listing $listing) {
        $stmt = $pdo->prepare(
<<<EOT
INSERT OR IGNORE INTO image(URL, listing_id, description)
VALUES (:URL, :listing_id, :description)
EOT
        );

        $stmt->execute(array(
            ":URL"          => $URL,
            ":listing_id"   => $listing->id(),
            ":description"  => $description
        ));

        if ($stmt->rowCount() !== 1) {
            return NULL;
        }

        return new Image($pdo, $URL, $description, $listing, $pdo->lastInsertId());
    }

    public function id() {
        return $this->id;
    }

    public static function getImages(PDO $pdo, Listing $listing) {
        $result = array();

        $stmt = $pdo->prepare(
<<<EOT
SELECT * FROM image where listing_id = :listing_id
EOT
        );

        $stmt->execute(array(
            ":listing_id"   => $listing->id(),
        ));

        while($row = $stmt->fetch()) {
            //$result[] = array($row['URL'], $row['description']);
            $result[] = new Image($pdo, $row['URL'], $row['description'], $listing, $row['id']);
        }  

        return $result;
    }
}

class Test extends PHPUnit_Framework_TestCase {
    protected $db;

    protected function setUp() {
        $this->db = createDatabase();
        createTables($this->db);
    }

    public function testCreatingSingleListing() {
        $listing1 = Listing::create($this->db, "Listing 1");   
        $this->assertEquals(1, $listing1->id());
    }


    public function testCreatingMultipleListings() {
        $listing1 = Listing::create($this->db, "Listing 1");
        $listing1 = Listing::create($this->db, "Listing 2");   
        $this->assertEquals(2, $listing1->id());
    }

    public function testReturningListingReturnsNullWhenNonexistence() {
        $this->assertNull(Listing::get($this->db, 1));
    }

    public function testReturningCreatedListing() {
        $Listing1 = Listing::create($this->db, "Listing 1");   
        $this->assertEquals("Listing 1", Listing::get($this->db, 1)->description);
    }

    public function testSavingListing() {
        $listing1 = Listing::create($this->db, "Listing 1");
        $listing1->description = "new";
        $listing1->save();
        $this->assertEquals("new", Listing::get($this->db, 1)->description);
    }

    public function testListingHasNoImagesWhenJustCreated() {
        $listing1 = Listing::create($this->db, "Listing 1");
        $this->assertEquals(array(), $listing1->getImages());
    }

    public function testAddingImageToListing() {
        $listing1 = Listing::create($this->db, "Listing 1");
        $image1 = Image::create($this->db, "http://localhost:12343/dfdfx/45.png", "first image", $listing1); 
        $this->assertEquals(array($image1), $listing1->getImages());
    }

    public function testAddingImagesToListing() {
        $listing1 = Listing::create($this->db, "Listing 1");
        $image1 = Image::create($this->db, "http://localhost:12343/dfdfx/45.png", "first image", $listing1);
        $image2 = Image::create($this->db, "http://localhost:12343/df/46.png", "second image", $listing1);
        $this->assertEquals(array($image1, $image2), $listing1->getImages());
    }

}
1 голос
/ 14 июля 2011

Не уверен, какие ошибки у вас возникают, так как вам кажется, что процесс достаточно ясен в вашей голове. В первый раз, когда я сделал это, я использовал этот урок в качестве руководства, и все отлично сработало: http://php.about.com/od/phpwithmysql/ss/Upload_file_sql.htm

Могу ли я предложить вместо сохранения файла в базе данных ?? Так меньше проблем с безопасностью!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...