Jump to content

Efficiency Question


947740

Recommended Posts

I've been doing php off and on for a couple years now.  I can do a lot with it...but I do not know if the way I do it is the best way available.  So what I'm going to do here is post some code along with a basic idea behind it and ask if it is one of the better ways to do it.  If it's not, any input as to how to better do it would be greatly appreciated.

 

As to what this code does...the first section checks if the form has been submitted.  If it has, then it processes the data and creates a new link.

 

the included file config.php contains the constants used to connect to the database, as well as including a functions.php file, (where the getHeader() and getFooter() functions are located.)

 

The second section (only processed if a form has not been submitted) displays the form to create a new link.  If you want to see what the final product looks like it can be found here.

 

I understand my request here is probably different than usual, as the script does what it's meant to do.  I'm just concerned about my practices and the efficiency in which I do things.  Thanks ahead of time.

 

Anyways...the php code:

 

<?php

// Show all errors

error_reporting(E_ALL);
ini_set('display_errors', '1'); 

session_start();

define('ROOT', "../");

require_once(ROOT . "includes/config.php");

$mysqli = new mysqli(HOST,USERNAME,PASSWORD,DATABASE);

// Form was submitted, we need to create the link
if(isset($_POST['submit'])) {
// Sanitize data
$ln = $mysqli->real_escape_string($_POST['link_name']);
$color = $mysqli->real_escape_string($_POST['color']);
$pl = $mysqli->real_escape_string($_POST['parent_link']);
$article = $mysqli->real_escape_string($_POST['article']);
$url = $mysqli->real_escape_string($_POST['url']);
	if($url != "") {
	$article = "";
	}

$admin = $_POST['admin'];
	if($mysqli->query("INSERT INTO links (link_name,color,parent_link,article,admin,url) VALUES ('$ln','$color','$pl','$article','$admin','$url')")) {
	$_SESSION['msg'] = "Link added.";
	}
	else {
	$_SESSION['msg'] = "Link was not added: " . $mysqli->error;
	}

header("Location: " . ROOT);
exit();
}

$header = getHeader(CREATE_LINK_ID);

echo $header;

// Get list of articles

$result = $mysqli->query("SELECT * FROM articles WHERE nolink = 0");
$articlebox = "<select name='article'>";
$articlebox .= "<option value=''>None";
while($row = $result->fetch_row()) {
$articlebox .= "<option value='{$row[0]}'>{$row[1]}";
}
$articlebox .= "</select>";

// Get list of links

$result = $mysqli->query("SELECT ID,link_name FROM links WHERE parent_link = 0");
$linkbox = "<select name='parent_link'>";
$linkbox .= "<option value='0'>None";
while($row = $result->fetch_row()) {
$linkbox .= "<option value='{$row[0]}'>{$row[1]}";
}
$linkbox .= "</select>";

echo <<<END
<div id='center'>
<div id='floaty'>
<form name='form' action='create.php' method='POST'>
Link name: <input type='text' name='link_name' />
Color: <input type='text' name='color' value='#ffffff' />
<br />
Parent link: $linkbox

Admin Only: <select name='admin'>
<option value='0'>No
<option value='1'>Yes
</select>
<br />
URL: <input type='text' name='url' />
Article: $articlebox
<br />
<input type='submit' name='submit' value='Create Link' />
</form>
</div>
</div>
END;

$footer = getFooter();

echo $footer;

?>

 

Link to comment
Share on other sites

// Form was submitted, we need to create the link
if(isset($_POST['submit'])) {

See this thread: http://www.phpfreaks.com/forums/index.php/topic,167898.15.html

 

error_reporting(E_ALL);
ini_set('display_errors', '1'); 

session_start();

define('ROOT', "../");

require_once(ROOT . "includes/config.php");

$mysqli = new mysqli(HOST,USERNAME,PASSWORD,DATABASE);

I imagine the head of all your files looks like that.  Seems like a lot of redundant typing to me.  Why not use mod_rewrite and send all requests through index.php.  Then you can perform those steps in index.php and later include() the necessary page based on $_SERVER['REQUEST_URI'].

 

$ln = $mysqli->real_escape_string($_POST['link_name']);

You're not checking that 'link_name' is present in post and opening your script up for errors.  You should do something like:

$link_name = post_val( 'link_name' );

// And if link_name has a default you can use then you can do:
$link_name = post_val( 'link_name', 'Untitled Link' );

function post_val( $name, $default = false ) {
    return array_key_exists( $name, $_POST ) ? $_POST[ $name ] : $default;
}

 

$_SESSION['msg'] = "Link was not added: " . $mysqli->error;

I imagine this message is displayed to the user.  Unless you're the only one using this, there's never a good reason to display database message errors to users.  Instead you should log the database error so you [the developer] can see what happened.  The user should get something more generic like Unable to add link at this time.

 

$result = $mysqli->query("SELECT * FROM articles WHERE nolink = 0");

You should avoid select * and instead list the columns you are expecting by name.  This prevents the database from passing unnecessary data over the socket, which speeds things up.  And if this table grows to have more columns and many, many rows select * can negate the benefit of any indexes you place on the table.

 

$articlebox .= "<option value=''>None";

You're not closing any of your option tags.  If this page is supposed to be XHTML strict [which is ideal in most circumstances], then not closing tags makes it invalid markup.  Invalid markup will adversely affect any CSS or JavaScript you write.  Often times JavaScript (dealing with the DOM) or CSS rules don't work as expected and it's often because of bad markup.  But people don't realize this so they write 5 times more CSS or JavaScript to work around the problem instead of just closing the necessary tags.

 

$articlebox .= "<option value='{$row[0]}'>{$row[1]}";

What's $row[0]?  What's $row[1]?  That's not very descriptive.  Oh sure, today they're name and description.  But what happens if you add a column before description?  Then $row[1] is no longer description and your code breaks.  Instead why not use:

while( $row = $result->fetch_object() ) {
  echo $row->id . ' ' . $row->name . PHP_EOL; // assuming columns are id and name
}

fetch_object() is the best!

 

"<option value='{$row[0]}'>{$row[1]}";

Why are you not using htmlentities()?  Should be:

$row[0] = htmlentities( $row[0], ENT_QUOTES );
$row[1] = htmlentities( $row[1], ENT_QUOTES );
"<option value='{$row[0]}'>{$row[1]}";

 

<form name='form' action='create.php' method='POST'>

I'm pretty sure attributes are supposed to be lower-case nowadays.

 

$footer = getFooter();

echo $footer;

Could be

echo getFooter();

Link to comment
Share on other sites

One last thing.  All of that free-floating code in the global namespace, it gives me bad feelings.  I like to really, really make sure my pages and their variables are completely self-contained.

 

Therefore I usually define a base Page class with common functions like:

redirect( $url, $msg = null ) // redirect to $url, optionally save a message in $_SESSION to redirect page to display / use

get_session_message() // returns saved session message

post_val( $name, $default ); // retrieves from $_POST with optional default

query_val( $name, $default ); // retrieves from $_GET with optional default

is_post() // returns true if post page... i.e: return count( $_POST ) > 0

get_db() // returns handle to database

db_escape( $val ) // escapes database value so I don't have to

markup_escape( $val, $entities = true, $striptags = true ) // will strip tags and htmlentities a value

abstract function run(); // derived pages must provide this method

 

Now your page can look like this:

<?php
//TODO
// Page should be in a different file
class Page {
    protected function post_val( $name, $default = false ) {
        return array_key_exists( $name, $_POST ) ? $_POST[ $name ] : $default;
    }

    protected function get_db() {
        static $db = null;
        if( $db === null ) {
            // TODO Change path to correct one
            include( dirname( __FILE__ ) . '/db.config.php' );
            $db = new mysqli( HOST, USERNAME, PASSWORD, DATABASE );
        }
        return $db;
    }

    protected function insert_query( $table, $values ) {
        $db = $this->get_db();
        $cols = array_keys( $values );
        foreach( $cols as $key => $col ) {
            $cols[ $key ] = "`{$col}`";
        }
        foreach( $values as $col => $value ) {
            $values[ $col ] = $db->real_escape_string( $value );
        }
        return "
            insert into `{$table}`
            ( " . implode( ', ', $cols ) . " ) values
            ( " . implode( ', ', $values ) . " )
            ";
    }

    protected function log( $msg ) {
        // TODO Write $msg to a log file of your choosing.
    }
}

class CreateLinkPage extends Page {

    public function run() {
        if( $this->is_post() ) {
            $vals = array();
            $vals[ 'link_name' ] = $this->post_val( 'link_name' );
            $vals[ 'color' ] = $this->post_val( 'color' );
            $vals[ 'parent_link' ] = $this->post_val( 'parent_link' );
            $vals[ 'article' ] = $this->post_val( 'article' );
            $vals[ 'url' ] = $this->post_val( 'url' );
            $vals[ 'admin' ] = $this->post_val( 'admin' );
            if( $vals[ 'url' ] != '' ) {
                $vals[ 'artucle' ] = '';
            }
            $insert_qry = $this->insert_query( 'links', $values );
            $db = $this->get_db();
            if( $db->query( $insert_qry ) ) {
                $this->redirect( 'new_url.php', "Link added successfully." );
            }else{
                $this->log( $db->error );
                $this->redirect( 'new_url.php', "Unable to add link at this time." );
            }
        }

        $html = '';
        // TODO rest of your code for non-post
        echo $html;
    }

}

$pg = new CreateLinkPage();
$pg->run();
?>

Link to comment
Share on other sites

Thanks A LOT roopurt.  That's the kind of insight I was looking for.  I wasn't even expecting that much, but it's really appreciated.

 

I apologize for the delayed response, but I've had a lot of non-programming stuff bogging me down recently.  Hopefully I can get back on the ball here and knock this site out!

 

Cheers.

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.