[英]Using PHP to upload images to a folder while saving descriptions to a database
用戶決定為他們的分類列表上傳多張圖片。 我需要做的是:
我的表模式是這樣設置的(簡化):
ad_id | member_id | category | subcategory | ... | photo_0_href | photo_0_desc ... | etc.
有人可以指導我完成整個過程嗎? 謝謝。
<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>
<?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";
}
?>
我知道我的上傳。php 尚未配置為多個圖像文件,但這是一個開始。
我使用$_SESSION['file_n_desc']
將描述保存到數據庫中。 我只需要弄清楚如何將糟糕的圖像上傳到文件夾,然后將位置保存到數據庫中。
我還需要將圖像重命名為隨機字符串(以防止圖像被覆蓋)。 我知道我可以用rand()
function 做到這一點。
當對文件輸入使用數組語法時,文件索引是最后一個鍵。 例如, $_FILES["file"]["name"]
是一個文件名數組。 要獲取第 i 個文件的信息,您需要訪問$_FILES["file"]["name"][$i]
, $_FILES["file"]["size"][$i]
&C。
$_FILES
中的某些數據(例如名稱)來自客戶端,因此不可信(即先驗證)。 對於文件名,您可以首先使用realpath
來驗證目標文件路徑名是否安全,或者在組裝目標路徑名之前使用basename
或pathinfo
提取所提供名稱的最后一個組件。
您提供的(不完整的)數據庫架構看起來就像您在同一個表中為每個圖像提供了兩列。 在關系 model 下,對多關系使用單獨的表建模:
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;
否則,當圖像數量少於最大數量時,您將打破零一無窮大規則並浪費空間。
請注意,您可以對文件描述字段使用數組語法,以便更輕松地處理它們。 將它們命名為“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)) {
如果文件具有有效的圖像 header 但 rest 無效,即使這樣也可能被愚弄。 您可以使用圖像庫(例如 GD 或 ImageMagick)通過檢查是否可以成功將文件作為圖像打開來驗證文件。
不確定您遇到了什么錯誤,因為您似乎對這個過程很清楚。 我第一次這樣做時,我以本教程為指導,一切正常: http://php.about.com/od/phpwithmysql/ss/Upload_file_sql.htm
我可以建議將文件存儲在數據庫中嗎? 這樣可以減少安全問題!
PS:我覺得你是一個初學者,我想我在PHP 新手:如何編寫好的代碼
2) 將圖像保存到指定的文件夾
move-uploaded-file應該可以工作。 想到的是您沒有設置正確的寫入權限來移動文件。 您使用哪種服務器(Linux/Windows/MacOSX)? function 作為布爾值(結果)返回什么?
另一件事:我需要將圖像重命名為隨機字符串(以防止圖像被覆蓋)。 我知道我可以用 rand() function 來做到這一點,但我忘了在我原來的帖子中提到它。
rand()
並不是真正隨機的,並且可能會給出重復的文件名。 uniqid將是唯一的
編輯:我想出使用 $_SESSION['file_n_desc'] 將描述保存到數據庫中。 我只需要弄清楚如何上傳這些該死的東西,然后將位置保存到數據庫中。
當您沒有覆蓋 session 時使用 session 時,您使用的不是 MySQL 數據庫,而是文件系統。 您可以閱讀本教程以在數據庫中存儲 session 。 標准的 session 在關閉瀏覽器時被清除(僅針對該會話)。 試試這個代碼:
<?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
但是當您關閉瀏覽器時,session_id 已更改並且您的計數器已重置,並且您會看到 output 看起來像。
0
fiakdijmmk38i40f39fm8u5mi4
1
fiakdijmmk38i40f39fm8u5mi4
能夠以畫廊設置的形式調用其分類列表中的圖像和描述
我使用PDO (Good Read)來執行(My)SQL。 我使用phpunit進行了單元測試(TDD)。 為了訪問數據庫,我在 memory 模式下使用了 SQLite(非常適合進行 SQL 測試)=> new PDO('sqlite::memory:');
. 我試圖遵循鮑勃叔叔的三個規則(Good Read)。
通常,您將其拆分為多個文件。 每個 class 在一個單獨的文件中。 每個 class 都應在單獨的文件中進行隔離(松散耦合)測試。
我使用了 map “Listing to Image”的外鍵。 我認為這個例子經過了相當徹底的測試,但現在我真的該睡覺了,所以我不確定;)。
<?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());
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.