Php 添加带有详细信息(名称、数量、多个图像)的产品,并在另一个页面中检索它们
假设我有一个具有属性id、名称、数量、图像、描述的产品表。我还有另一个具有属性id、productId、imagepath的表图像 我有一张这样的表格Php 添加带有详细信息(名称、数量、多个图像)的产品,并在另一个页面中检索它们,php,mysql,forms,file-upload,Php,Mysql,Forms,File Upload,假设我有一个具有属性id、名称、数量、图像、描述的产品表。我还有另一个具有属性id、productId、imagepath的表图像 我有一张这样的表格 <form method="post" action=""> < input type="text" name="name" /> < input type="text" name="quantity" /> < input type="file" name="images[]" mu
<form method="post" action="">
< input type="text" name="name" />
< input type="text" name="quantity" />
< input type="file" name="images[]" multiple/>
< input type="text" name="description" />
</form>
我刚开始学习PHP,我对PHP和mysql的使用不是很熟练,但我真的很想知道如何添加一个带有详细信息(名称、数量、描述)的产品并将两个或多个图像发送到我的数据库,然后在另一个页面中检索具有详细信息的同一产品以及属于此特定产品的两个或多个图像
我真的不知道创建一个产品和一个图像表(图像表将获得每次上传的productId和StoreImagePath)是否是解决这个问题的最佳方法。
因此,我希望找到一个简单或可靠的方法来做这件事,如果你能举例说明,这将对我有很大帮助。
提前感谢。是的,您应该这样做:一个“产品”表和一个“产品图像”表。后者应该有一个外键集:“product_id”列应该引用“products”表中的“id”。并且两个表都必须将“id”列作为主键 我希望您能理解代码:
- addProduct.php包含表单并添加产品。php显示所选产品的详细信息
- 成功添加产品(在addProduct.php中)后会出现一个链接,以便在getProduct.php中显示其详细信息
- 将在config.php文件中提供的路径处自动创建一个目录。我将目录路径设置为“上载”。上传时,此路径将前置到图像文件名,并保存在“产品\图像”的相应列“文件名”中
- 多文件上传
- 提交包含所提供产品详细信息的表单时,将验证用户输入值,并在表单上显示相应的错误消息
- 除了addProduct.php和getProduct.php之外,还有两个辅助文件:config.php保存了一些关于上传的常量;php保存数据库连接实例及其所需的常量
- 数据库访问操作是使用PDO/MySQLi和所谓的
由于您的问题不在Stackoverflow的帮助范围内,您将获得否决票。这类问题应该通过遵循一些教程、阅读书籍等来解决。Stackoverflow是指您尝试过的一些击败您的代码。提交一次尝试,并在出错的地方寻求帮助。到时候人们会帮助你的。阅读@Alan我已经阅读了很多教程,尝试了很多代码,但到目前为止都没有任何效果,我越来越困惑,所以我决定寻求更详细的帮助,帮助别人思考问题。当我意识到这个解释得很好的答案时,我感激不尽。但我总是收到这样的警告:“警告:常数可能只会在第11行的C:\xampp\htdocs\sav\config.php中计算为标量值警告:in_array()希望参数2是数组,字符串在第60行的C:\xampp\htdocs\sav\addProduct.php中给出”,并且在我提交表单“文件扩展名”Douglas.jpg时出现此错误消息“无效。允许的扩展名:JPG、JPEG、PNG或GIF。文件“Jackson.jpg”的扩展名无效。允许的扩展名:JPG、JPEG、PNG或GIF。“@LabelleDoriane欢迎您。这是因为您的PHP版本小于5.6。在此版本之前,不能将数组定义为常量值。我强烈建议您更新到PHP>=7.0,因为7.0版附带了许多重要的良好更改。无论如何,您当前的问题很容易解决:我重新编辑了我的答案,例如page config.php和addProduct.php。搜索其中的注释@changed_2018-02-17_14.28
。在那里我做了一些改变。总共大约有3行代码:config.php中有1行代码,addProduct.php中有2行代码。@LabelleDoriane P.s:如果您升级到PHP7,则无需进行更改。谢谢。我会更新的。我将阅读关于PDO和Prepared语句的内容,因为我只使用了MySQLI面向对象的方式。为了改变它,使它适合我的方式coding@LabelleDoriane那就好了。因为我也建议你从MySQLi改为PDO。PDO在许多方面与MySQLi相似,但它更加优雅,易于使用和实现。这也是唯一的oo风格。我建议您从这里学习:。
CREATE TABLE `products` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(100) DEFAULT NULL,
`quantity` int(11) DEFAULT NULL,
`description` varchar(150) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `products_images` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`product_id` int(11) unsigned DEFAULT NULL,
`filename` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `product_id` (`product_id`),
CONSTRAINT `products_images_ibfk_1` FOREIGN KEY (`product_id`) REFERENCES `products` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
<?php
// Upload configs.
define('UPLOAD_DIR', 'uploads');
define('UPLOAD_MAX_FILE_SIZE', 10485760); // 10MB.
//@changed_2018-02-17_14.28
define('UPLOAD_ALLOWED_MIME_TYPES', 'image/jpeg,image/png,image/gif');
<?php
// Db configs.
define('HOST', 'localhost');
define('PORT', 3306);
define('DATABASE', 'tests');
define('USERNAME', 'root');
define('PASSWORD', 'root');
define('CHARSET', 'utf8');
/*
* Enable internal report functions. This enables the exception handling,
* e.g. mysqli will not throw PHP warnings anymore, but mysqli exceptions
* (mysqli_sql_exception).
*
* MYSQLI_REPORT_ERROR: Report errors from mysqli function calls.
* MYSQLI_REPORT_STRICT: Throw a mysqli_sql_exception for errors instead of warnings.
*
* @link http://php.net/manual/en/class.mysqli-driver.php
* @link http://php.net/manual/en/mysqli-driver.report-mode.php
* @link http://php.net/manual/en/mysqli.constants.php
*/
$mysqliDriver = new mysqli_driver();
$mysqliDriver->report_mode = (MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
/*
* Create a new db connection.
*
* @see http://php.net/manual/en/mysqli.construct.php
*/
$connection = new mysqli(HOST, USERNAME, PASSWORD, DATABASE, PORT);
<?php
include 'config.php';
include 'connection.php';
$productSaved = FALSE;
if (isset($_POST['submit'])) {
/*
* Read posted values.
*/
$productName = isset($_POST['name']) ? $_POST['name'] : '';
$productQuantity = isset($_POST['quantity']) ? $_POST['quantity'] : 0;
$productDescription = isset($_POST['description']) ? $_POST['description'] : '';
/*
* Validate posted values.
*/
if (empty($productName)) {
$errors[] = 'Please provide a product name.';
}
if ($productQuantity == 0) {
$errors[] = 'Please provide the quantity.';
}
if (empty($productDescription)) {
$errors[] = 'Please provide a description.';
}
/*
* Create "uploads" directory if it doesn't exist.
*/
if (!is_dir(UPLOAD_DIR)) {
mkdir(UPLOAD_DIR, 0777, true);
}
/*
* List of file names to be filled in by the upload script
* below and to be saved in the db table "products_images" afterwards.
*/
$filenamesToSave = [];
$allowedMimeTypes = explode(',', UPLOAD_ALLOWED_MIME_TYPES);
/*
* Upload files.
*/
if (!empty($_FILES)) {
if (isset($_FILES['file']['error'])) {
foreach ($_FILES['file']['error'] as $uploadedFileKey => $uploadedFileError) {
if ($uploadedFileError === UPLOAD_ERR_NO_FILE) {
$errors[] = 'You did not provide any files.';
} elseif ($uploadedFileError === UPLOAD_ERR_OK) {
$uploadedFileName = basename($_FILES['file']['name'][$uploadedFileKey]);
if ($_FILES['file']['size'][$uploadedFileKey] <= UPLOAD_MAX_FILE_SIZE) {
$uploadedFileType = $_FILES['file']['type'][$uploadedFileKey];
$uploadedFileTempName = $_FILES['file']['tmp_name'][$uploadedFileKey];
$uploadedFilePath = rtrim(UPLOAD_DIR, '/') . '/' . $uploadedFileName;
if (in_array($uploadedFileType, $allowedMimeTypes)) {
if (!move_uploaded_file($uploadedFileTempName, $uploadedFilePath)) {
$errors[] = 'The file "' . $uploadedFileName . '" could not be uploaded.';
} else {
$filenamesToSave[] = $uploadedFilePath;
}
} else {
$errors[] = 'The extension of the file "' . $uploadedFileName . '" is not valid. Allowed extensions: JPG, JPEG, PNG, or GIF.';
}
} else {
$errors[] = 'The size of the file "' . $uploadedFileName . '" must be of max. ' . (UPLOAD_MAX_FILE_SIZE / 1024) . ' KB';
}
}
}
}
}
/*
* Save product and images.
*/
if (!isset($errors)) {
/*
* The SQL statement to be prepared. Notice the so-called markers,
* e.g. the "?" signs. They will be replaced later with the
* corresponding values when using mysqli_stmt::bind_param.
*
* @link http://php.net/manual/en/mysqli.prepare.php
*/
$sql = 'INSERT INTO products (
name,
quantity,
description
) VALUES (
?, ?, ?
)';
/*
* Prepare the SQL statement for execution - ONLY ONCE.
*
* @link http://php.net/manual/en/mysqli.prepare.php
*/
$statement = $connection->prepare($sql);
/*
* Bind variables for the parameter markers (?) in the
* SQL statement that was passed to prepare(). The first
* argument of bind_param() is a string that contains one
* or more characters which specify the types for the
* corresponding bind variables.
*
* @link http://php.net/manual/en/mysqli-stmt.bind-param.php
*/
$statement->bind_param('sis', $productName, $productQuantity, $productDescription);
/*
* Execute the prepared SQL statement.
* When executed any parameter markers which exist will
* automatically be replaced with the appropriate data.
*
* @link http://php.net/manual/en/mysqli-stmt.execute.php
*/
$statement->execute();
// Read the id of the inserted product.
$lastInsertId = $connection->insert_id;
/*
* Close the prepared statement. It also deallocates the statement handle.
* If the statement has pending or unread results, it cancels them
* so that the next query can be executed.
*
* @link http://php.net/manual/en/mysqli-stmt.close.php
*/
$statement->close();
/*
* Save a record for each uploaded file.
*/
foreach ($filenamesToSave as $filename) {
$sql = 'INSERT INTO products_images (
product_id,
filename
) VALUES (
?, ?
)';
$statement = $connection->prepare($sql);
$statement->bind_param('is', $lastInsertId, $filename);
$statement->execute();
$statement->close();
}
/*
* Close the previously opened database connection.
*
* @link http://php.net/manual/en/mysqli.close.php
*/
$connection->close();
$productSaved = TRUE;
/*
* Reset the posted values, so that the default ones are now showed in the form.
* See the "value" attribute of each html input.
*/
$productName = $productQuantity = $productDescription = NULL;
}
}
?>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=yes" />
<meta charset="UTF-8" />
<!-- The above 3 meta tags must come first in the head -->
<title>Save product details</title>
<script src="https://code.jquery.com/jquery-3.2.1.min.js" type="text/javascript"></script>
<style type="text/css">
body {
padding: 30px;
}
.form-container {
margin-left: 80px;
}
.form-container .messages {
margin-bottom: 15px;
}
.form-container input[type="text"],
.form-container input[type="number"] {
display: block;
margin-bottom: 15px;
width: 150px;
}
.form-container input[type="file"] {
margin-bottom: 15px;
}
.form-container label {
display: inline-block;
float: left;
width: 100px;
}
.form-container button {
display: block;
padding: 5px 10px;
background-color: #8daf15;
color: #fff;
border: none;
}
.form-container .link-to-product-details {
margin-top: 20px;
display: inline-block;
}
</style>
</head>
<body>
<div class="form-container">
<h2>Add a product</h2>
<div class="messages">
<?php
if (isset($errors)) {
echo implode('<br/>', $errors);
} elseif ($productSaved) {
echo 'The product details were successfully saved.';
}
?>
</div>
<form action="addProduct.php" method="post" enctype="multipart/form-data">
<label for="name">Name</label>
<input type="text" id="name" name="name" value="<?php echo isset($productName) ? $productName : ''; ?>">
<label for="quantity">Quantity</label>
<input type="number" id="quantity" name="quantity" min="0" value="<?php echo isset($productQuantity) ? $productQuantity : '0'; ?>">
<label for="description">Description</label>
<input type="text" id="description" name="description" value="<?php echo isset($productDescription) ? $productDescription : ''; ?>">
<label for="file">Images</label>
<input type="file" id="file" name="file[]" multiple>
<button type="submit" id="submit" name="submit" class="button">
Submit
</button>
</form>
<?php
if ($productSaved) {
?>
<a href="getProduct.php?id=<?php echo $lastInsertId; ?>" class="link-to-product-details">
Click me to see the saved product details in <b>getProduct.php</b> (product id: <b><?php echo $lastInsertId; ?></b>)
</a>
<?php
}
?>
</div>
</body>
</html>
<?php
include 'config.php';
include 'connection.php';
if (!isset($_GET['id']) || empty($_GET['id']) || !is_numeric($_GET['id'])) {
$errors[] = 'You must select a product in order to see its details!';
} else {
$productId = $_GET['id'];
/*
* Get the product details.
*/
$sql = 'SELECT *
FROM products
WHERE id = ?
LIMIT 1';
$statement = $connection->prepare($sql);
$statement->bind_param('i', $productId);
$statement->execute();
/*
* Get the result set from the prepared statement.
*
* NOTA BENE:
* Available only with mysqlnd ("MySQL Native Driver")! If this
* is not installed, then uncomment "extension=php_mysqli_mysqlnd.dll" in
* PHP config file (php.ini) and restart web server (I assume Apache) and
* mysql service. Or use the following functions instead:
* mysqli_stmt::store_result + mysqli_stmt::bind_result + mysqli_stmt::fetch.
*
* @link http://php.net/manual/en/mysqli-stmt.get-result.php
* @link https://stackoverflow.com/questions/8321096/call-to-undefined-method-mysqli-stmtget-result
*/
$result = $statement->get_result();
/*
* Fetch data (all at once) and save it into an array.
*
* @link http://php.net/manual/en/mysqli-result.fetch-all.php
*/
$products = $result->fetch_all(MYSQLI_ASSOC);
/*
* Free the memory associated with the result. You should
* always free your result when it is not needed anymore.
*
* @link http://php.net/manual/en/mysqli-result.free.php
*/
$result->close();
$statement->close();
if (!$products) {
$errors[] = 'No product found.';
} else {
$product = $products[0];
$productName = $product['name'];
$productQuantity = $product['quantity'];
$productDescription = $product['description'];
/*
* Get the images list for the provided product.
*/
$sql = 'SELECT *
FROM products_images
WHERE product_id = ?';
$statement = $connection->prepare($sql);
$statement->bind_param('i', $productId);
$statement->execute();
$result = $statement->get_result();
$images = $result->fetch_all(MYSQLI_ASSOC);
$result->close();
$statement->close();
$connection->close();
}
}
?>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=yes" />
<meta charset="UTF-8" />
<!-- The above 3 meta tags must come first in the head -->
<title>Product details</title>
<script src="https://code.jquery.com/jquery-3.2.1.min.js" type="text/javascript"></script>
<style type="text/css">
body {
padding: 30px;
}
.product-details tr td {
padding: 5px;
}
.product-details .label {
font-weight: 700;
}
.product-images {
margin-top: 30px;
}
.product-images tr td {
padding: 10px;
font-weight: 700;
background-color: #eee;
}
.product-images .label {
color: #fff;
font-weight: 700;
background-color: #8daf15;
}
.product-images img {
max-width: 400px;
display: inline-block;
float: left;
}
</style>
</head>
<body>
<div class="page-container">
<h2>Product details</h2>
<?php
if (isset($errors)) {
echo implode('<br/>', $errors);
exit();
}
?>
<table class="product-details">
<tr>
<td class="label">Name</td>
<td><?php echo $productName; ?></td>
</tr>
<tr>
<td class="label">Quantity</td>
<td><?php echo $productQuantity; ?></td>
</tr>
<tr>
<td class="label">Description</td>
<td><?php echo $productDescription; ?></td>
</tr>
</table>
<table class="product-images">
<tr>
<td class="label">Images</td>
</tr>
<?php
foreach ($images as $image) {
$imageId = $image['id'];
$imageFilename = $image['filename'];
?>
<tr>
<td>
<img src="<?php echo $imageFilename; ?>" alt="" />
</td>
</tr>
<?php
}
?>
</table>
</div>
</body>
</html>