728x90

I am relatively new to programming and OOP in PHP. I tried to create a Simple Login Register Script using my basic knowledge of OOP. I'm sure my code can be better in a lot of way. I'm trying to code better and learn new things.

Be harsh, please find out as many small noob mistakes as you can. Suggestions and Feedbacks are always welcomed !

Config.php

<?php 
class dbConfig {
   public $host;
   public $username;
   public $password;
   public $dab;
   public $conn;

public function dbConnect() {
    $this->conn = mysqli_connect($this->host,$this->username,$this->password);

    if (!$this->conn) {
        die("Connection failed: " . mysqli_connect_error());
    }
    else{
        echo "Connected successfully to server";
    }

    $db_selected = mysqli_select_db($this->conn, $this->dab);

    if (!$db_selected) {
        // if the given database doesn't exists
        // creates new database with that name
        $db_sql = 'CREATE DATABASE chatapp';

        // verify the database is created
        if (mysqli_query($this->conn, $db_sql)){
            echo "Database chatapp already exists or created successfully\n";
        } else {
            echo 'Error creating database: ' . mysqli_error() . "\n";
        }
    }

    // creating tables
    $table_sql = "CREATE TABLE IF NOT EXISTS users (".
            "uid INT PRIMARY KEY AUTO_INCREMENT,".
            "username VARCHAR(30) UNIQUE,".
            "password VARCHAR(50),".
            "name VARCHAR(100),".
            "email VARCHAR(70) UNIQUE); ";

    // verify the table is created
        if (mysqli_query($this->conn, $table_sql)) {
            echo "Table: users already exists or created successfully\n";
        } else {
            echo 'Error creating table: ' . mysqli_error($table_sql) . "\n";
        }
}
}

$obj = new dbConfig();

$obj->host = 'localhost';
$obj->username = 'root';
$obj->password = '';
$obj->dab = 'chatapp';
$obj->dbConnect();

login.php

<?php
include('config.php');
session_start();

if($_SERVER["REQUEST_METHOD"] == "POST")
{
// username and password sent from Form
$emailusername = mysqli_real_escape_string($obj->conn,$_POST['emailusername']); 
$password = mysqli_real_escape_string($obj->conn,$_POST['password']); 
$password = md5($password);

$sql="SELECT uid FROM users WHERE username='$emailusername' or email = '$emailusername' and password='$password'";
$result=mysqli_query($obj->conn,$sql);
$row=mysqli_fetch_array($result,MYSQLI_ASSOC);
$active=$row['active'];
$count=mysqli_num_rows($result);


// If result matched $username and $username, table row must be 1 row
if($count==1)
{
$_SESSION['login_user'] = $emailusername;
header("location: welcome.php");
}
else 
{
$error="Your Login Name or Password is invalid";
}
}
?>
<<!DOCTYPE html>
<html>
<head>
    <title>Login</title>
</head>
<body>
    <form action="login.php" method="post">
        <label>UserName or Email:</label>
        <input type="text" name="emailusername"/><br />
        <label>Password :</label>
        <input type="password" name="password"/><br/>
        <input type="submit" value=" Submit "/><br />
    </form>
</body>
</html>

register.php

    <?php
include('config.php');
if(isset($login_session))
{
header("Location: login.php");
}
if ($_SERVER["REQUEST_METHOD"] == "POST") 
{
$username = mysqli_real_escape_string($obj->conn,$_POST['username']); 
$password = mysqli_real_escape_string($obj->conn,$_POST['password']); 
$name     = mysqli_real_escape_string($obj->conn,$_POST['name']); 
$email    = mysqli_real_escape_string($obj->conn,$_POST['email']); 

$password = md5($password);

$sql ="SELECT uid from users WHERE username = '$username' or email = '$email'";
$register_user = mysqli_query($obj->conn,$sql) or die(mysqli_error($sql));
$no_rows = mysqli_num_rows($register_user);

if($no_rows == 0)
{
    $sql2 = "INSERT INTO users(username, password, name, email) values ('$username', '$password', '$name', '$email')";
    $result = mysqli_query($obj->conn, $sql2) or die(mysqli_error($sql2));
    echo "Registration Successfull!";
}
else{
    echo "Registration Failed.";
}
}
?>
<!DOCTYPE html>
<html>
<head>
    <title>Register</title>
</head>
<body>
    <form action="register.php" method="post">
    <label>UserName or Email:</label>
    <input type="text" name="username" required/><br />
    <label>Password :</label>
    <input type="password" name="password" required/><br/>
    <label>Full Name :</label>
    <input type="text" name="name" required/><br/>
    <label>Email :</label>
    <input type="email" name="email" required/><br/>
    <input type="submit" value=" Submit "/><br />
    </form>
</body>
</html>

logout.php

<?php
session_start();
if(session_destroy())
{
header("Location: login.php");
}
?>

welcome.php

<?php
include('lock.php');
?>
<html>
<head><title>Home</title>
</head>
<body>
<h1>Welcome <?php echo $login_session; ?></h1>
</body>
</html>

lock.php

<?php
include('config.php');
session_start();
$user_check=$_SESSION['login_user'];

$ses_sql=mysqli_query($obj->conn,"SELECT username FROM users WHERE username='$user_check' ");

$row=mysqli_fetch_array($ses_sql,MYSQLI_ASSOC);

$login_session=$row['username'];

if(!isset($login_session))
{
header("Location: login.php");
}
?>

While copy-pasting the code here, I was getting feeling that I made the code a bit more lengthier for such a small task. Please let me know how to minify the code and other various aspects of my code.

shareimprove this question

At first glance

After a quick glance at your code, it reminded me of this review I posted a while back. Much like that piece of code, a couple of (broadly similar) issues jumped out:

  • Wrapping procedural style code in a class with some methods does not qualify as OOP.
  • Your one and only method (dbConnect) is fundamentally flawed and unsafe. Not in the least because it relies on the user (the code that creates an instance of your class) to set the properties manually before calling the method. What if these properties aren't set? create a __construct method (constructor) that requires the user to pass the connection params to the class when an instance is created, much in the same way that mysqli or PDO require these params to be passed.
  • There is some sanitation of values used in your query, but you really ought to look into prepared statements
  • Methods don't echo, and they certainly don't die. If they encounter a problem, they throw new RuntimeException, or some other exception that accurately describes the problem (InvalidArgumentExceptionBadMethodCallException, ...).
  • Your dbConnect method just does too much. Its name suggests it merely connects, when in reality, it echoes, creates tables and never closes the DB connection. Calling dbConnecttwice is possible, your code doesn't take that into account.
  • Coding standards are important. PHP doesn't have any official standards (yet), but the PHP-FIG standards are adopted by all major players (Symfony, Zend, Apple, Composer, CakePHP, ...). You'd do well following them, too
  • md5, as a hash, is no longer secure. It first started showing weaknesses back in 1998, was deemed unsafe about ten years ago, and back in 2010, a single-block collision was found. At the very least, use sha1, but even so: PHP supports blowfish, sha256 and sha512 just as easily.
  • When hashing passwords, you'd also do well using salt. Don't just hash the password as-is. Add some random string that only you know. Even so, PHP has a very useful, easy to use and helpful function called password_hash. Use it.
  • You seem to be confused as to the point of OOP. In PHP, and many other languages, OOP isn't used to reduce the size of your code base (look at Java, or even C++). It's about making a sizable code base more manageable, more structured. Yes, when you first start writing OO code, you'll find yourself writing a lot more code than you were used to. The benefits are that, after a while, you'll find yourself re-using bits of code that you had written for another project. OOP enable (or at least facilitates) abstraction, separation of concerns and force developers to think more about what task should go where in the application. If you want to write OO code, don't go looking for ways to reduce the amount of code you write, look for ways to improve the overall structure of your project, and optimize what component has access to what functionality at any given time.

I'll be going into all of these issues in detail, each time updating this answer, but for now, I'd urge you to check out the links I provided here, and google some OOP terms like the SOLID principles

If you want to avoid lengthy code at all costs, then perhaps you should consider learning another language than PHP. Perl, for example, allows you to write obfuscated code a lot easier. Mind you, PHP has a couple of tricks up its sleeve, as this "Hello world" demonstrates (source):

<?=${[${[${[${[${[${[${[${[${${![]}.=[]}.=${![]}{!![]}]}.=${!![${[${[${[${[${[${[${[]}++]}
++]}++]}++]}++]}++]}++]}{![]+![]+![]}]}.=${[${[${[${[]}++]}++]}++]}{![]+![]}
.${![]}{![]+![]+![]}]}.=${[${![]}=${![]}{!![]}]}{!![${!![${!![${![]}++]}++]}++]}^
${!![${[${[${[]}++]}++]}++]};

Update 1
As you requested, some more details on the second issue I mentioned (about the dbConnectmethod being flawed). Your code, as it stands now expects the user to write something like:

$obj = new dbConfig();
$obj->host = '127.0.0.1';
$obj->username = 'user';
$obj->password = 'pass';
$obj->dab = 'dbname';
$obj->dbConnect();

But what if, because most devs are lazy, someone writes:

$db = new DbConfig();//classes should start with an UpperCase
//some code
someFunction($db);
//where someFunction looks like:
function someFunction(DbConfig $db)
{
    $db->dbConnect();//<== ERROR! host, user, pass... nothing is set
}

The instance could be created in a different file as the line that is calling dbConnect, so debugging this kind of code is hellish. You could re-write each piece of code that calls dbConnect to make sure all of the required properties have been set correctly, but what if they aren't? And what is "correct"? That's something the instantiating code should know, not the code that calls dbConnect. Luckily, you can use a constructor to ensure all parameters are known:

class DbConnect
{
    /**
     * @var string
     */
    protected $host = null;

    /**
     * @var string
     */
    protected $username = null;

    /**
     * @var string
     */
    protected $pass = null;//null for no pass

    /**
     * @var string
     */
    protected $dbName = null;

    /**
     * @var mysqli
     */
    protected $conn = null;

    public function __construct($host, $user, $pass = null, $db = null)
    {
        $this->host = $host;
        $this->user = $user;
        $this->pass = $pass
        $this->dbName = $db;
    }

}

Now, whenever an instance is created, the host and user must be passed to the constructor, if not, PHP will throw up a fatal error. So you'll have to use the class like so:

$db = new DbConnect('127.0.0.1', 'root', '', 'chatapp');

This reduces the users' code (where your class is being used), and makes the instances behave more predictably.

You may have noticed that I've changed the visibility from public to protected. That's because public properties can be reassigned on the go, without any validation on their new value whatsoever. That's dangerous. Instead, I suggest you add some getters and setters for the properties that you want to expose (like the database):

public function setDbName($name)
{
    if (!is_string($name))
    {//dbName MUST be a string, of course, so if it isn't, notify the user
        throw new InvalidArgumentException(
            sprintf(
                '%s expects name argument to be a string, instead saw "%s"',
                __METHOD__,
                gettype($name)
            )
        );
    }
    $this->dbName = $name;
    return $this;
}

Using this method, you can also check if the instance is currently holding an active db connection, clean up whatever needs to be cleaned up (closing cursors, freeing results, ...) and (re)connect or select the new db on that connection.
On the user side, using these setters is as simple as:

$instance->setDbName('foobar');
//but:
$instance->setDbName(array());
//InvalidArgumentException
//message: DbConnect::setDbName expects name argument to be a string, instead saw "array"

Given that your class clearly tries to abstract the nitty-gritty of the rather messy mysqli API away from the user (which I can understand), it's also important that the user needn't worry about closing the connection in time. When your instance of DbConnect goes, then so must the DB connection itself go. For that, a simple desctructor would do the job just fine:

public function __destruct()
{
    if ($this->conn instanceof mysqli)
        this->conn->close();//or mysqli_close($this->conn);
    $this->conn = null;//optional
}

Now you can rest assured that, in case someone writes this:

$db = new DbConnect('127.0.0.1', 'root');
$db->dbConnect();
//...code here
$db = null;//or unset($db), or $db just goes out of scope

The connection will be closed automatically. Naturally, for all of these changes to take effect, you'll have to refactor your dbConnect method somewhat, but that's something I'll try to cover in the next update.

shareimprove this answer
   
Yes, I was really confused of OOP. Thank you for your comment. Well to be honest, I wasn't aware of the real objective of OO code.I would love to hear more from you. for now can you explain 2nd point a bit more ? Thank you for your time. – RajeebTheGreat Dec 30 '14 at 11:47
   
@RajeebTheGreat: You're welcome. I will update this answer, and focus on your code a bit more. When I find the time (later today probably), I'll post an update explaining the 2nd point a bit more, and providing some suggestions as to how to approach things – Elias Van Ootegem Dec 30 '14 at 12:09
   
@RajeebTheGreat: Added the first of, probably, many updates just now, focusing mainly on the second issue I pointed out – Elias Van Ootegem Dec 30 '14 at 15:38


728x90


I'm not sure what's going wrong here. I was just following a tutorial online and these errors popped up.

I'm getting the following errors

Error

Notice: Undefined variable: db in C:\xampp\htdocs\wisconsindairyfarmers\admin\login.php on line 7

Fatal error: Call to a member function query() on null in C:\xampp\htdocs\wisconsindairyfarmers\admin\login.php on line 7

Code

<?php
$db = new mysqli('127.0.0.1', 'root', '', 'wisconsindairyfarmers');
?>

<?php
require '../db/connect.php';
require '../functions/general.php';

    function user_exists($username){
        //$username = sanitize($username);
        $result = $db->query("SELECT COUNT(UserId) FROM users WHERE UserName = '$username'");
        if($result->num_rows){
        return (mysqli_result($query, 0) == 1) ? true : false;
    }}

if(empty($_POST) === false){

    $username = $_POST['username'];
    $password = $_POST['password'];

    if(empty($username) === true || empty($password) === true){ 
        echo 'You need to enter a username and password';
    }
    else if(user_exists($username) === false) {
        echo 'We can\'t find that username.';
    }
}

?>
shareimprove this question
3 
Your $db variable is inside a function and thus out of scope from the code that defines it. Declare it global, or better, pass it as an argument to your function. See the PHP manual on scope – user1864610 Jun 23 '15 at 2:22 
   
I changed the variables, and the first error is fixed, but I'm still getting : Fatal error: Call to undefined function mysqli_result() – MPStimpson Jun 23 '15 at 2:32
   
I think that is because you are using OOP on the first part and procedural for the the results. – Rasclatt Jun 23 '15 at 2:38
   
I'm kind of new to php, how do I go about fixing that? – MPStimpson Jun 23 '15 at 2:41
   
I think that's because mysqli_result() is not a function. I'm really not clear what that piece of code is trying to do, but mysqli_result() doesn't exist in PHP. – user1864610 Jun 23 '15 at 2:41

First, you declared $db outside the function. If you want to use it inside the function, you should put this at the begining of your function code:

global $db;

And I guess, when you wrote:

if($result->num_rows){
        return (mysqli_result($query, 0) == 1) ? true : false;

what you really wanted was:

if ($result->num_rows==1) { return true; } else { return false; }
shareimprove this answer
   
I'm not getting any errors anymore, but I can't seem to get into the 'user_exists($username) === false' when I'm testing do you have any other wisdom to share with me today :) – MPStimpson Jun 23 '15 at 4:08
   
Yes, your SQL query will always return 1 row, with 1 field saying the amount of users equals to username. Change that to "SELECT * FROM users WHERE UserName = '$username'" and it will work – Juan Carlos Alvez Balbastro Jun 24 '15 at 17:41
   
I figured that out, but thank you very much! You've been very helpful! That's what I get for blindly following tutorials – MPStimpson Jun 26 '15 at 1:06


'WEB > jQuery' 카테고리의 다른 글

jQuery change() Method  (0) 2018.01.14
PHP array_push  (0) 2018.01.14
Fatal error: Call to a member function fetch_array() on a non-object  (0) 2018.01.14
달력 - 날짜입력기(Date Picker)  (0) 2018.01.14
javascript comma and uncomma  (0) 2018.01.14
728x90
Why would the following code produce the above error the 3rd itteration?

while ($row_comp = $comp->fetch_array())
{
      $comp_count++;
      $comp_id = $row_comp['TID'];            
      $SqlString = "select * from pers where TID = \"$comp_id\"";
      echo "str = ".$SqlString."<br>";
      $pers = $conn->query($SqlString);
      while ($row_pers = $pers->fetch_array())
      {

The screen output looks like this:
str = select * from pers where TID = "10019706"
str = select * from pers where TID = "10019771"
str = select * from pers where TID = "10019779"

Fatal error: Call to a member function fetch_array() on a non-object in /home/langsyst/public_html/Lansco/Fix_Data_2A.php on line 58

Line 58 is the 2nd while
breeze351
Asked: 
breeze351
1 Solution
breeze351Author Commented: 
I forgot to add that I checked the 3rd sql statement and it does work.
Kim WalkerWeb Programmer/TechnicianCommented: 
The error means that $pers does not contain a query result possibly due to a problem with the db connection $conn. This could be a scope issue. Is the code you posted part of a function and if so, is the variable $conn defined within that same function?

Otherwise, we have another error to deal with and we need to determine what that is. Do you have error reporting turned on? If it is turned on and you're not seeing an error, please replace your code with the following and take note of the additions I've added for exposing the error. My first change is on line 7 and then I've added code after the end of the second while loop.
while ($row_comp = $comp->fetch_array())
{
      $comp_count++;
      $comp_id = $row_comp['TID'];            
      $SqlString = "select * from pers where TID = \"$comp_id\"";
      echo "str = ".$SqlString."<br>";
      if ($pers = $conn->query($SqlString) ) {
	      while ($row_pers = $pers->fetch_array()) {
	      	...
	      }
	  } else {
	  	if ($conn->error) {
	  		echo "{$conn->error}<br>SQL = $SqlString";
	  	} else {
	  		echo '$conn is a(n) '. gettype($conn);
	  	}
	  }
}

 Open in new window

Dave BaldwinFixer of ProblemsCommented: 
The usual reason is that the query failed.
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

breeze351Author Commented: 
Kim
How do I turn on the error reporting
breeze351Author Commented: 
Kim 
This is weird?!?!?!
I modified the code per your example.  I don't get an error message, however, if I keep refreshing the program, it will give me one more record before it craps out!
Kim WalkerWeb Programmer/TechnicianCommented: 
OK. This suggests that your first query is returning a TID value that doesn't exist in the pers table. In other words, the outer loop doesn't always have the right conditions for the inner loop.

To turn on error reporting, place these two lines at the beginning of your PHP page.
error_reporting(E_ALL);
ini_set('display_errors','on');

 Open in new window

breeze351Author Commented: 
I still don't get an error message other the "Fatal error....."
And again, it keeps giving me one more record before it fails.

I've attached the code.  It's small, I'm just trying to clean up some garbage data.
Thought this would be a piece of cake, after all how hard could it be!
Fix_Data_2A.php
Kim WalkerWeb Programmer/TechnicianCommented: 
Is the fatal error still on the inner while loop (line 61)?
Kim WalkerWeb Programmer/TechnicianCommented: 
One more modification (see lines 13-14, 22-24):
$comp_count = 0;
$per_count = 0;		
$SqlString = "select * from comp where ALFA = \"    \" and COMPANY = \"    \"";
$comp = $conn->query($SqlString);
while ($row_comp = $comp->fetch_array())
{
	$comp_count++;
	$comp_id = $row_comp['TID'];		
	$SqlString = "select * from pers where TID = \"$comp_id\"";
	echo "str = ".$SqlString."<br>";
	if ($pers = $conn->query($SqlString))
	{
		if ($pers->num_rows > 0)
		{
			while ($row_pers = $pers->fetch_array())
			{
				$pers_id = $row_pers['PNID'];
				$SqlString = "delete from pers where TID = '$comp_id' and PNID = '$pers_id'";
				$pers = $conn->query($SqlString);
				$per_count++;
			}
		} else {
			echo "<p>No records found for query $SqlString</p>\n";
		}
	}
	else 
	{
  		if ($conn->error) 
		{
  			echo "{$conn->error}<br>SQL = $SqlString";
	  	} 
		else 
		{
  			echo '$conn is a(n) '. gettype($conn);
  		}
	}
}

 Open in new window

breeze351Author Commented: 
No joy!
I didn't think it would work because it keeps blowing up on the while statement.
Try this yourself (I'm not worried about the data, I have backups and it's really not current).

Go to:
1: http://langsystems.net/Lansco/
(you need to do this for the session vars)
2: http://langsystems.net/Lansco/Fix_Data_2A.php

Look at the last "TID"# in the query, then refresh the page.  You'll get the next record.

There are only 234 records that match the 1st while loop.  Do I have to hit refresh 234 times? :)
Kim WalkerWeb Programmer/TechnicianCommented: 
AHAH! So the while loop iterates once then fails. It is because the while loop is attempting to read another record from the $pers result but the $pers result is being overwritten within the while loop. Change this
				$SqlString = "delete from pers where TID = '$comp_id' and PNID = '$pers_id'";
				$pers = $conn->query($SqlString);

 Open in new window

to
				$SqlString = "delete from pers where TID = '$comp_id' and PNID = '$pers_id'";
				$conn->query($SqlString);

 Open in new window

There is no need to store the results of the delete into a variable unless you need to view results such as affected_rows. If you still want to store those results, store them in a new variable instead of reusing $pers.
breeze351Author Commented: 
Thank you, Thank you!!!!!!!!!!!!!!

I just copied the $conn->query statement from code up above.  I knew how to delete the record but sometimes you can't see something so stupid.

Thank you again.
Glenn


'WEB > jQuery' 카테고리의 다른 글

PHP array_push  (0) 2018.01.14
Fatal error: Call to a member function query() on null  (0) 2018.01.14
달력 - 날짜입력기(Date Picker)  (0) 2018.01.14
javascript comma and uncomma  (0) 2018.01.14
[jQuery] following sidebar  (0) 2018.01.14
728x90
자바스크립트 날짜입력기입니다.
각종 날짜입력 폼에 타이핑 대신 사용하면 됩니다.
원래는 우체국에서 쓰던 팝업소스인데 레이어 스타일로 변경하였습니다.

테스트 :
IE8, 파이어폭스8, 크롬15, 오페라11, 사파리5

&lt;script language="JavaScript" src="date_picker.js"&gt;&lt;/script&gt; &lt;input type="text" name="target_date"&gt; &lt;input type="button" value="달력보기" onClick="datePicker(event,'target_date')"&gt; &lt;br&gt; &lt;input type="text" name="target_date"&gt; &lt;input type="button" value="달력보기" onClick="datePicker(event,'target_date',1)"&gt; 동일한 name의 타겟인 경우 세번째 인자의 키값으로 구분합니다. 세번째 인자가 생략되면 기본값은 0입니다.   
 

date_picker.js





+ Recent posts