So I have a problem with updating a mysql table via mysqli in php.
The database connection and class:
<?php
class testDB extends mysqli {
private static $instance = null;
private $user = "tester";
private $pass = "tester01";
private $dbName = "testdb";
private $dbHost = "localhost";
public static function getInstance() {
if (!self::$instance instanceof self) {
self::$instance = new self;
}
return self::$instance;
}
public function __clone() {
trigger_error('Clone is not allowed.', E_USER_ERROR);
}
public function __wakeup() {
trigger_error('Deserializing is not allowed.', E_USER_ERROR);
}
private function __construct() {
parent::__construct($this->dbHost, $this->user, $this->pass, $this->dbName);
if (mysqli_connect_error()) {
exit('Connect Error (' . mysqli_connect_errno() . ') '
. mysqli_connect_error());
}
parent::set_charset('utf-8');
}
public function verify_credentials ($username, $password){
$username = $this->real_escape_string($username);
$password = $this->real_escape_string($password);
$result = $this->query("SELECT 1 FROM users WHERE user_username = '" . $username . "' AND user_password = '" . $password . "'");
return $result->data_seek(0);
}
public function get_vitae() {
return $this->query("SELECT * FROM vitae");
public function update_vitae($text, $id) {
$text = $this->real_escape_string($text);
$this->query("UPDATE vitae SET vitae_text=".$text." WHERE vitae_id = ".$id);
}
}
?>
Here's the page code:
Above the header we check the login by making sure there is a session started; then import the database class and the rest is called upon resubmitting the form to this same page:
<?php
session_start();
if (!array_key_exists("username", $_SESSION)) {
header('Location: index.php');
exit;
}
require_once("includes/db.php");
$vitae_empty = false;
if ($_SERVER['REQUEST_METHOD'] == "POST") {
if ($_POST['text'] == "") {
$vitae_empty = true;
} else if ($_POST["text"]!="") {
testDB::getInstance()->update_vitae($_POST["text"], $_POST["id"]);
header('Location: manage.php' );
exit;
}
}
?>
In the body (the header and the rest of the html is imported via a 'require_once'):
<section>
<div class="grid_3 header_line"><h2>Update for CV</h2></div>
<div class="grid_3">
<?php
$result = testDB::getInstance()->get_vitae();
$vitae = mysqli_fetch_array($result);
?>
<form name="editvitae" action="editvitae.php" method="POST">
<textarea name="text" rows="50" cols="100"><?php echo $vitae['vitae_text'];?></textarea><br/>
<?php if ($vitae_empty) echo "Please enter some text.<br/>";?>
<input type="hidden" name="id" value="<?php echo $vitae["vitae_id"];?>" /> <br/>
<input type="submit" name="savevitae" value="Save Changes"/>
</form>
</div>
<div class="grid_3">
<p>‹ back to management consol</p>
</div>
</section>
After the 'body' tag:
<?php mysql_free_result($result);?>
As you can see this pulls the 'vitae' text from the database then loops it to the same page with changes to update the table. It also check's to see that the 'text' box is not empty.
This code works in another application; I'm not understanding why it won't work here. AND before you start warning me about injection and security I have stripped most of it out trying to find the problem with the update. It WILL go back in once I can figure that out.
I have tried stripping the text check; different variable names; dumping the post values into an array before updating the database; putting the post values into static variables; checking all my spellings etc...
I'm missing something and I feel like it's going to be simple.
Anytime an UPDATE is run through mysqli you need to run the $mysqli->commit(); method.
Your new update_vitae would be:
public function update_vitae($text, $id) {
$text = $this->real_escape_string($text);
$this->query("UPDATE vitae SET vitae_text=".$text." WHERE vitae_id = ".$id);
$this->commit;
}
mysqli also has an autocommit feature that can be toggled on or off:
$this->autocommit(true); //on
$this->autocommit(false); //off
So the answer was indeed simple. It was my escaping on the update string as Andrewsi suggested. Here's the update that fixed it:
public function update_vitae($text, $id) {
$text = $this->real_escape_string($text);
$this->query("UPDATE vitae SET vitae_text = '$text' WHERE vitae_id = ".$id);
}
Thanks for the help!
I've been designing websites for almost 10 years, but I'm just now getting into 'real' php coding instead of using prepared classes and dreamweaver's built in functions. Far to much to learn but it's fun in my limited spare time.
$result = $this->query("SELECT 1 FROM users WHERE user_username = '" . $username . "' AND user_password = '" . $password . "'");
Be careful with using logical ANDs for user authentication. It may be more wise to completely validate the username first before going after any kind of password. I say this in regard to the many examples of people inserting --; WHERE 1=1 -- and stuff like that (not specifically this statement, however). Sure, this may require two queries, but at least you only have to process one piece of information to determine if a visitor is valid. Another advantage might be saving processing because you won't have to deal with hashing/encrypting the user's password in your app or at the database (until the username has been verified).
Related
What I want is to get and store the last inserted ID, but I am not sure how. The scenario is, after a user add a record he/she will be redirected to a page that will show him/her of the summary of what he/she saved. But I am not sure how I can do that, to retrieved the recently added record.
I have a class which look like this record.php
<?php
class Record {
private $conn;
private $table_name_1 = "name_of_the_table_1";
private $table_name_2 = "name_of_the_table_2";
public $name;
public $age;
public function __construct($db){
$this->conn = $db;
}
function newRecord(){
$query = "INSERT INTO " . $this->table_name_1 . " SET name=:name;
INSERT INTO " . $this->table_name_2 . " SET age=:age";
$stmt = $this->conn->prepare($query);
$this->name=$this->name;
$this->age=$this->age;
$stmt->bindParam(':name', $this->name);
$stmt->bindParam(':age', $this->age);
if($stmt->execute()){
return true;
}else{
return false;
}
}
}
?>
now I have another php form that create and add record, the code is something like this add_record.php
<?php
inlude_once 'db.php'
inlude_once 'record.php'
$database = new Database();
$db = $database->getConnection();
$record = new Record($db);
?>
<?php
if($_POST) {
$record->name=$_POST['name'];
$record->age=$_POST['age'];
if(record->record()){
header("Location:{$home_url}view_recently_added_record.php?action=record_saved");
}
else{
echo "Unable to save";
}
}
?>
The idea is to save the query to two different table and the same time automatically record the auto increment ID of table 1 to table 2 so that they have a relationship. I am thinking I can do that if I can store immediately the ID from table 1 and assigned it a variable maybe so it can be automatically saved to table two using a new query or function maybe. Is this possible? does it make sense? and another thing I wanted to display the recently recorded data immediately to the user. Thank you.
You can return $stmt->insert_id or -1 insteaf of boolean in the newRecord function:
function newRecord(){
...
if($stmt->execute()){
return $stmt->insert_id;
}else{
return -1;
}
}
and use the value to redirect like this:
$newrecord = record->newRecord();
if($newrecord != -1) {
header("Location:{$home_url}view_recently_added_record.php?action=record_saved&id=".$newrecord);
}
else{
echo "Unable to save";
}
i bet there are scripts out there already about this, but I'm creating this project just for fun and to test my knowledge, now i just want the public's opinions, and if you guys find a way I could improve feel free to share as well to comment against it.
My question is simply how to create a good salt. after reading the manual, and a few book chapters this is what i came up with. Although i feel like my salt should be longer for security. what should I change?
Here is my user class. please check genSalt() function and guide me to figure out how to improve my results.
<?php
if(!defined('ACCESS_CORE')){
echo 'Permission Not Granted';
exit;
}
class user{
private $_email;
private $_pass;
private $_db;
private $_url;
function __construct(){
$this->_db = $this->db();
$this->_url = 'localhost'; //change this to ur url
if(isset($_POST['user_login'])){
$this->_email = $this->clean($_POST['user_email']); //sanitize later
$this->_pass = $this->clean($_POST['user_password']);
}
}
protected function db(){
$db = parse_ini_file('../contra.conf');
$this->_db = new mysqli($db['host'], $db['user'], $db['pass'], $db['name']);
if ($this->_db->connect_errno) {
trigger_error("Failed to connect to MySQL".$mysqli->connect_errno). $mysqli->connect_error;
}
}
protected function clean($string){
return mysql_real_escape_string($string); #TODO: add more options html etc
}
public function safeReferer(){
$ref = (isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : ''); //if there is a ref..
if(empty($ref) || strpos($ref, $this->_url)){
return true;
} else {
return false;
}
}
public function includeForm($message = ""){ #TODO: finish form view page
?>
<div id="logForm">
<h3>User Authentication Form</h3>
<?php echo ($message === "") ? '' : $message; ?>
<form id="loginForm" method="post" action="login.php">
<input type="text" name="user_email" />
<input type="password" name="user_password" />
<input type="submit" value="Login" name="user_login" />
<a href="/" >Forgot password?</a>
</form>
</div>
<?php ;
}
protected function genSalt($length) { #TODO: improve something is fishy
$prefix = '$2a$'.$length.'$'; //blowfish prefix
//base64 unique random alphanumeric
$uniqRand = base64_encode(mcrypt_create_iv($length, MCRYPT_DEV_URANDOM));
$modified_string = str_replace('+', '.', $uniqRand);
$salt = substr($modified_string, 0, $length);
return $prefix.$salt.'$';
}
protected function correctPass($password, $salt){ #TODO: change to prepared statement. best method?
$sql = "SELECT pass, s FROM users WHERE email = '$this->_email'";
if($result = $this->_db->query($sql)){
while ($row = $result->fetch_object()) {
if(cript($row['pass'], $row['s']) === $row['s']){
return true;
} else {
return false;
}
}
}
}
public function login(){
if($this->correctPass($this->_email, $this->_pass)){
echo 'create session, session cookie, start timeout, and redirect'; #TODO: copy login, finish page on form view
} else {
$message = '<h5>Please try again</h5>';
$message .= '<p>It looks like you have either entered a wrong user name or password.';
$this->includeForm($message);
}
}
// test function, similar function in register class
public function createPass($pass){
$salt = $this->genSalt(10);
$hash = crypt($pass, $salt);
echo $salt. '--';
echo 'hashed pass : '. $hash;
echo '<br> entered pass : '.$pass.'<br>';
if(crypt($pass, $hash) == $hash ){
echo 'true';
} else {
echo 'false';
}
}
}
?>
test function results...
$2a$10$WlUvRqsgZl$--
hashed pass : $2a$10$WlUvRqsgZl$$$$$$$$$$$. tRNdwECDQXhN07g4mIp82xxFCTUev3m
entered pass : mypassword
true
Why not consider the password_hash function? It also hashes but generates a random salt every time and uses blowfish by default. It requires PHP 5.5 or later, however.
I have following code for multiple database connections. It's not good design. Everything is static. But don't know how to improve it. i can add more functions like prepare query, but presently I want good/clean design. I tried to make multiton design pattern. The requirements is like, first I will connect with 1 database, then get database details of all other mysql clients, then loop and connect with each database and do something. So, I need multiple connections.
<?php
class db_class{
private static $instance = array();
private function __construct(){ }
public static function get_instance($type , $db_detail_array=array()){
$host = $db_detail_array['host'];
$username = $db_detail_array['username'];
$database = $db_detail_array['database'];
$password = $db_detail_array['password'];
if(empty($host) or empty($username) or empty($database) or empty($password)){
return;
}
if(empty(self::$instance[$type])) {
self::$instance[$type] = new mysqli($host, $username, $password, $database);
if (#self::$instance[$type]->connect_errno) {
echo self::$last_err = "Connect failed";
}
}
}
static function fetch_assoc($query,$type){
$db_query = self::run_query($query,$type);
$rows = array();
while($row = #$db_query->fetch_assoc()){
$rows[] = $row;
}
$db_query->free();
return($rows);
}
static function escape($type,$value){
$value = self::$instance[$type]->real_escape_string($value);
return($value);
}
static function run_query($query,$type){
self::$instance[$type]->ping();
$db_query = self::$instance[$type]->query($query);
if(self::$instance[$type]->error){
echo self::$last_err = self::$instance[$type]->error;echo "<p>$query, $type</p>";
return;
}
return($db_query) ;
}
static function num_rows($query,$type){
$db_query = self::run_query($query,$type);
$num_rows = $db_query->num_rows;
return($num_rows);
}
static function disconnect($type){
#self::$db_obj[$type]->close();
}
}
?>
Please have a look at PDO.
It is an unifier database object exposing a common and effective interface.
It supports server types other than mysql too.
Even using it plainly will be satisfactory.
If I declare a global variable such as a database connection of $mysqli how do I use that in a class. i am trying to use it in my user class. Do i store it as a public variable in the class or as a global in the function itself. I also think there is something wrong with my following code but I may be wrong.
class USER
{
function __constructor()
{
}
/*
* adds a new user
* returns FALSE on error
* returns user id on success
*/
function add_member($name, $email, $password)
{
global $mysqli;
$query = "INSERT INTO members
SET
user_name = {'$name'},
user_email = {'$email'},
password = ['$password'}";
$success = $mysqli -> query ($query);
if (!$success || $mysqli -> affected_rows == 0)
{
echo "<p> An error occurred: you just are not tough enough!!!</p>";
return FALSE;
}
$uid = $mysqli -> insert_id;
return $uid;
}
} // end class
$uc = new USER();
?>
<?php
require_once ('includes/classes/database.php');
require_once('includes/classes/user.php');
require_once('includes/header.php');
// if user submits a new registration
if (isset($_POST['name'],$_POST['email'],$_POST['pwd'],$_POST['pwd2']))
{
// validate input fields
$name = $_POST['name'];
$email = $_POST['email'];
$password = $_POST['pwd'];
$password2 = $_POST['pwd2'];
// if error fall through and redisplay page with errors
// if no errors update database and redirect to homepage
if ($uc->add_member($name, $email, $password) === FALSE)
{
echo "System Error. damn if I know what to do";
}
else
{
header("location: homepage.php");
}
}
You um... don't. Instead use a variable inside of the class:
class USER
{
private $mysql;
function __constructor($mysqli)
{
$this->mysqli = $mysqli;
}
function add_member($name, $email, $password)
{
$mysqli = $this->mysqli;
/* yada yada */
Couple of issues by the way:
// You want the ' outside of the {}
$query = "INSERT INTO members
SET
user_name = '{$name}',
user_email = '{$email}',
password = '{$password}'";// there was a [ not a {
You also want to call mysqli_real_escape_string on all of those variables. Or better yet use mysqli_bind_param and a prepared statement.
I might be missing something here, I'm not sure. A Google search didn't really help either.
What I'm wanting to do is call the databaseServer class and use its methods within my userControl class. Here is my lib_class.php file:
<?php
include('definitions.php');
class databaseServer {
var $con;
var $db;
var $close;
var $qry;
var $sql;
function connect($host,$user,$pw,$db) {
$this->con = mysql_connect($host,$user,$pw);
if (!$this->con) {
die('Could not connect: ' . mysql_error());
}
else {
echo "Database Connected";
}
$this->selectDb($db);
}
function selectDb($database) {
$this->db = mysql_select_db($database,$this->con);
if (!$this->db) {
echo "Could not Select database";
}
else {
echo "Database Selected";
}
}
function disconnect() {
$this->close = mysql_close($this->con);
if ($this->close) {
echo "Disconnected";
}
}
function query($test) {
if (!mysql_query($test)) {
die("Error: " . mysql_error());
}
}
} // databaseServer
class cookie {
var $expireTime;
function set($name,$value,$expiry) {
$this->expireTime = time()+60*60*24*$expiry;
setcookie($name,$value,$expireTime);
}
function delete($name) {
setcookie($name,"",time()-3600);
}
function check($name) {
if (isset($_COOKIE["$name"]))
echo "Cookie Set";
else
echo "Cookie failed";
}
} //cookie
class userControl {
public function __construct(databaseServer $server) {
$this->server = new databaseServer();
}
function createUser($uname,$pword) {
$this->server->connect(DB_HOST,DB_USER,DB_PASS,DB_NAME);
$result = $this->server->query("SELECT * FROM user_list WHERE uname='" . $this->server->real_escape_string($uname) . "'");
if ($this->result->num_rows() === 0) {
if ($this->server->query("INSERT INTO user_list (uname, pword)
VALUES ('" . $this->server->real_escape_string($uname) . "','" . $this->server->real_escape_string($pword) . "')") {
echo "User Added Successfully!";
}
else {
echo "Error Adding User!";
}
}
else {
echo "User Already Exists!";
}
} // createUser
} // userControl
?>
However, this isn't working and I can't see why. My databaseServer and cookie classes work fine when I omit the userControl class from the file, so I know the error must be in that class somewhere. OOP is something I'm trying to learn and I keep stumbling.
The echoes in the databaseServer class are there only for me to test it. I am implementing the classes in an index.php file as follows:
<?php
include('definitions.php');
include('class_lib.php');
$bmazed = new databaseServer();
$bmazed->connect(DB_HOST,DB_USER,DB_PASS,DB_NAME);
$sql = "INSERT INTO blah
VALUES ('testing 92')";
$bmazed->query($sql);
$bmazed->disconnect();
// $control = new userControl();
// $uname = "Test1";
// $pword = "test1";
// $control->createUser($uname,$pword);
echo "<br />";
echo "<br />";
?>
Lines have been commented out for testing purposes, so I don't have to keep re-writing code.
I really have no idea where the problem lies, I've checked syntax and everything seems fine.
You cannot assign class or instance properties that depend on runtime information when you declare the classes. See the chapter on Class Properties in the PHP Manual.
Change the class to read:
class userControl
{
protected $_server;
public function __construct ()
{
$this->_server = new databaseServer();
}
}
Also, to access class/instance members, you have to to use the $this keyword, e.g.
$this->_server->connect();
On a sidenote, while composition is fine, aggregation is better. It helps your code staying maintainable and loosely coupled, which means it will be much easier to replace components, for instance when writing UnitTests. So consider changing the constructor to use Dependency Injection.
Initialize $server in the constructor:
class userControl {
private $server;
function __construct() {
$this->server = new databaseServer();
}
function createUser($uname,$pword) {
$this->server->connect(DB_HOST,DB_USER,DB_PASS,DB_NAME);
$result = $this->server->query("SELECT * FROM user_list WHERE uname='" . $this->server->real_escape_string($uname) . "'");
if ($this->result->num_rows() === 0) {
if ($this->server->query("INSERT INTO user_list (uname, pword) VALUES ( '" . $this->server->real_escape_string($uname) . "','" . $this->server->real_escape_string($pword) . "')") {
echo "User added Succesfully";
}
else {
echo "Error Adding User";
}
else {
echo "User already exists";
}
}
}
For one, $server won't be accessible from within createUser() because it's in a different scope. PHP scope works a bit differently than one would expect from a C-style language.
Try either passing the $server to createUser(), or initializing the server in createUser(), in which case you should probably have a getServer() function so that you're not initializing it needlessly.
The third option is by far the worst, which is doing "global $server" at the top, inside the function. But it's very bad practice. You have been warned.
Last but not least, you should probably look for COUNT(*) than * in the SQL query, because otherwise you're selecting all the users. :)
If you want further information on PHP's scope, see here (highly recommended):
http://php.net/manual/en/language.variables.scope.php
Hope it helps!
The syntactical stuff certainly was a problem. But even more fundamentally wrong with my code was the fact that the databaseServer->query method doesn't return a value. Making it return a value fixed the problem.
I think, sometimes, it's not possible to see the wood for the trees. :)