我在写这个问题之前进行了搜索,但没想到我会找到答案,因为我的问题是特定的。
无论如何,我一直关注Kevin Skoglund在Lynda.com上的PHP Beyond the Basics课程,并且在将照片上传到数据库(MySQL)时遇到了麻烦。这是我第一次真正涉足OOP并且已经陷入停滞状态。我一直在查看我的文件超过一周,尽力解决问题,没有运气。
奇怪的是,我尝试直接在本地计算机上使用练习文件,并且我得到了相同的错误(包括我的信息,如数据库信用和目录名称)。
基本上我的问题是,当我尝试上传照片时,它会从临时目录移动到images目录,但永远不会进入数据库。我得到了数据库查询失败'它发布时的消息和mysql中的照片表保持为空。我看到错误来自哪里(在database.php confirm_query()内部),但没有关于问题的倾向。我知道我能够与数据库进行通信,因为在创建照片类/表之前,我能够将用户添加到数据库中的用户表。
以下是我的文件。我添加了我认为与此问题相关的三个,但是将整个项目压缩并将其上传到Dropbox。任何帮助/见解都会非常感激!!
*请注意我已将databaseObject中的函数放入照片类
photo_upload.php:
<?php
require_once('../../includes/initialize.php');
if (!$session->is_logged_in()) {
redirect_to("login.php");
}
$max_file_size = 1048576; //expressed in bytes
// 10240 = 10kb
// 102400 = 100kb
//1048576 = 1mb
//10485760 = 1mb
$message = "";
if (isset($_POST['submit'])) {
$photo = new Photograph();
$photo->caption = $_POST['caption'];
$photo->attach_file($_FILES['file_upload']);
if ($photo->save()) {
//success
$message = "Photograph uploaded successfully";
} else {
//failure
$message = join("<br>", $photo->errors);
}
}
include_layout_template('admin_header.php');
?>
<h2>Photo Upload</h2>
<?php echo output_message($message); ?>
<form action="photo_upload.php" enctype="multipart/form-data" method="post">
<input type="hidden" name="MAX_FILE_SIZE" value="<?php echo $max_file_size ?>">
<p><input type="file" name="file_upload"></p>
<p>Caption: <input type="text" name="caption" value=""></p>
<input type="submit" name="submit" value="upload">
</form>
<?php include_layout_template('admin_footer.php'); ?>
Photograph.php:
<?php
// If it's going to need the database, then it's
// probably smart to require it before we start.
require_once(LIB_PATH.DS.'database.php');
class Photograph extends DatabaseObject {
protected static $table_name="photographs";
protected static $db_fields=array('id', 'filename', 'type', 'size', 'caption');
public $id;
public $filename;
public $type;
public $size;
public $caption;
private $temp_path;
protected $upload_dir="images";
public $errors=array();
protected $upload_errors = array(
// http://www.php.net/manual/en/features.file-upload.errors.php
UPLOAD_ERR_OK => "No errors.",
UPLOAD_ERR_INI_SIZE => "Larger than upload_max_filesize.",
UPLOAD_ERR_FORM_SIZE => "Larger than form MAX_FILE_SIZE.",
UPLOAD_ERR_PARTIAL => "Partial upload.",
UPLOAD_ERR_NO_FILE => "No file.",
UPLOAD_ERR_NO_TMP_DIR => "No temporary directory.",
UPLOAD_ERR_CANT_WRITE => "Can't write to disk.",
UPLOAD_ERR_EXTENSION => "File upload stopped by extension."
);
// Pass in $_FILE(['uploaded_file']) as an argument
public function attach_file($file) {
// Perform error checking on the form parameters
if(!$file || empty($file) || !is_array($file)) {
// error: nothing uploaded or wrong argument usage
$this->errors[] = "No file was uploaded.";
return false;
} elseif($file['error'] != 0) {
// error: report what PHP says went wrong
$this->errors[] = $this->upload_errors[$file['error']];
return false;
} else {
// Set object attributes to the form parameters.
$this->temp_path = $file['tmp_name'];
$this->filename = basename($file['name']);
$this->type = $file['type'];
$this->size = $file['size'];
// Don't worry about saving anything to the database yet.
return true;
}
}
public function save() {
// A new record won't have an id yet.
if(isset($this->id)) {
// Really just to update the caption
$this->update();
} else {
// Make sure there are no errors
// Can't save if there are pre-existing errors
if(!empty($this->errors)) { return false; }
// Make sure the caption is not too long for the DB
if(strlen($this->caption) > 255) {
$this->errors[] = "The caption can only be 255 characters long.";
return false;
}
// Can't save without filename and temp location
if(empty($this->filename) || empty($this->temp_path)) {
$this->errors[] = "The file location was not available.";
return false;
}
// Determine the target_path
$target_path = SITE_ROOT .DS. 'public' .DS. $this->upload_dir .DS. $this->filename;
// Make sure a file doesn't already exist in the target location
if(file_exists($target_path)) {
$this->errors[] = "The file {$this->filename} already exists.";
return false;
}
// Attempt to move the file
if(move_uploaded_file($this->temp_path, $target_path)) {
// Success
// Save a corresponding entry to the database
if($this->create()) {
// We are done with temp_path, the file isn't there anymore
unset($this->temp_path);
return true;
}
} else {
// File was not moved.
$this->errors[] = "The file upload failed, possibly due to incorrect permissions on the upload folder.";
return false;
}
}
}
// Common Database Methods
public static function find_all() {
return self::find_by_sql("SELECT * FROM ".self::$table_name);
}
public static function find_by_id($id=0) {
$result_array = self::find_by_sql("SELECT * FROM ".self::$table_name." WHERE id={$id} LIMIT 1");
return !empty($result_array) ? array_shift($result_array) : false;
}
public static function find_by_sql($sql="") {
global $database;
$result_set = $database->query($sql);
$object_array = array();
while ($row = $database->fetch_array($result_set)) {
$object_array[] = self::instantiate($row);
}
return $object_array;
}
private static function instantiate($record) {
// Could check that $record exists and is an array
$object = new self;
// Simple, long-form approach:
// $object->id = $record['id'];
// $object->username = $record['username'];
// $object->password = $record['password'];
// $object->first_name = $record['first_name'];
// $object->last_name = $record['last_name'];
// More dynamic, short-form approach:
foreach($record as $attribute=>$value){
if($object->has_attribute($attribute)) {
$object->$attribute = $value;
}
}
return $object;
}
private function has_attribute($attribute) {
// We don't care about the value, we just want to know if the key exists
// Will return true or false
return array_key_exists($attribute, $this->attributes());
}
protected function attributes() {
// return an array of attribute names and their values
$attributes = array();
foreach(self::$db_fields as $field) {
if(property_exists($this, $field)) {
$attributes[$field] = $this->$field;
}
}
return $attributes;
}
protected function sanitized_attributes() {
global $database;
$clean_attributes = array();
// sanitize the values before submitting
// Note: does not alter the actual value of each attribute
foreach($this->attributes() as $key => $value){
$clean_attributes[$key] = $database->escape_value($value);
}
return $clean_attributes;
}
// replaced with a custom save()
// public function save() {
// // A new record won't have an id yet.
// return isset($this->id) ? $this->update() : $this->create();
// }
public function create() {
global $database;
// Don't forget your SQL syntax and good habits:
// - INSERT INTO table (key, key) VALUES ('value', 'value')
// - single-quotes around all values
// - escape all values to prevent SQL injection
$attributes = $this->sanitized_attributes();
$sql = "INSERT INTO ".self::$table_name." (";
$sql .= join(", ", array_keys($attributes));
$sql .= ") VALUES ('";
$sql .= join("', '", array_values($attributes));
$sql .= "')";
if($database->query($sql)) {
$this->id = $database->insert_id();
return true;
} else {
return false;
}
}
public function update() {
global $database;
// Don't forget your SQL syntax and good habits:
// - UPDATE table SET key='value', key='value' WHERE condition
// - single-quotes around all values
// - escape all values to prevent SQL injection
$attributes = $this->sanitized_attributes();
$attribute_pairs = array();
foreach($attributes as $key => $value) {
$attribute_pairs[] = "{$key}='{$value}'";
}
$sql = "UPDATE ".self::$table_name." SET ";
$sql .= join(", ", $attribute_pairs);
$sql .= " WHERE id=". $database->escape_value($this->id);
$database->query($sql);
return ($database->affected_rows() == 1) ? true : false;
}
public function delete() {
global $database;
// Don't forget your SQL syntax and good habits:
// - DELETE FROM table WHERE condition LIMIT 1
// - escape all values to prevent SQL injection
// - use LIMIT 1
$sql = "DELETE FROM ".self::$table_name;
$sql .= " WHERE id=". $database->escape_value($this->id);
$sql .= " LIMIT 1";
$database->query($sql);
return ($database->affected_rows() == 1) ? true : false;
// NB: After deleting, the instance of User still
// exists, even though the database entry does not.
// This can be useful, as in:
// echo $user->first_name . " was deleted";
// but, for example, we can't call $user->update()
// after calling $user->delete().
}
}
?>
database.php中:
<?php
require_once("config.php");
class MySQLDatabase {
//Step #1 open connection
private $connection;
function __construct() {//once you create an instance of this class it will automatically create the connection
$this->open_connection();
}
public function open_connection(){
$this->connection = mysqli_connect(DB_SERVER, DB_USER, DB_PASS, DB_NAME);
//Test the connection
if(mysqli_connect_errno()){//use errno because error returns an empty string if succesful
die('Database connection failed: '. mysqli_connect_error().
'('.mysqli_connect_errno().')');
}
}
//Step #2 preform database query
public function query($sql){
$result = mysqli_query($this->connection, $sql);
$this->confirm_query($result);
return $result;
}
private function confirm_query($result){
if(!$result){ //this is a check to make sure the query worked
die('Database query failed');
}
}
public function escape_value($string){
$escaped_string = mysqli_real_escape_string($this->connection, $string);
return $escaped_string;
}
//database neutral functions
//this is our database adapter which is called for mysql
public function fetch_array($result_set){
return mysqli_fetch_array($result_set);
}
public function num_rows($result_set) {
return mysqli_num_rows($result_set);
}
public function insert_id(){
//get the last id inserted over the current connection
return mysqli_insert_id($this->connection);
}
public function affected_rows(){
return mysqli_affected_rows($this->connection);
}
//Step #4 close connection
public function close_connection() {
if(isset($this->connection)){
mysqli_close($this->connection);
unset($this->connection);
}
}
}
$database = new MySQLDatabase();
?>
https://www.dropbox.com/s/oqdi2dz2mbkuwzz/photo_gallery.zip?dl=0
答案 0 :(得分:0)
经过多次挖掘后,我得出的结论是我的问题与我的代码无关。有一个sql设置,不允许我输入并清空字符串sqlmode=STRICT_TRANS_TABLES
。谢谢maxhb指出我的方向正确!!
我最终为解决这个问题所做的是创建一个my.conf
文件来更改默认设置(我在mac osx 10.11 btw上运行mysql 5.7.9)。奇怪的是,只有当我将这个文件放在两个位置.my.cnf
和/etc/mysql/my.cnf
时,才能使用以下文字:
[mysqld]
sql_mode=NO_ENGINE_SUBSTITUTION