Index
    Preface
      What This Book Is About
      What You Need to Know
      How This Book Is Organized
      How to Use This Book
      Conventions Used in This Book
      Using Code Examples
      How to Contact Us
      Web Site and Code Examples
      Acknowledgments
      Chapter 1.  Database Applications and the Web
      Section 1.1.  The Web
      Section 1.2.  Three-Tier Architectures
      Chapter 2.  The PHP Scripting Language
      Section 2.1.  Introducing PHP
      Section 2.2.  Conditions and Branches
      Section 2.3.  Loops
      Section 2.4.  Functions
      Section 2.5.  Working with Types
      Section 2.6.  User-Defined Functions
      Section 2.7.  A Working Example
      Chapter 3.  Arrays, Strings, and Advanced Data Manipulation in PHP
      Section 3.1.  Arrays
      Section 3.2.  Strings
      Section 3.3.  Regular Expressions
      Section 3.4.  Dates and Times
      Section 3.5.  Integers and Floats
      Chapter 4.  Introduction to Object-Oriented Programming with PHP 5
      Section 4.1.  Classes and Objects
      Section 4.2.  Inheritance
      Section 4.3.  Throwing and Catching Exceptions
      Chapter 5.  SQL and MySQL
      Section 5.1.  Database Basics
      Section 5.2.  MySQL Command Interpreter
      Section 5.3.  Managing Databases and Tables
      Section 5.4.  Inserting, Updating, and Deleting Data
      Section 5.5.  Querying with SQL SELECT
      Section 5.6.  Join Queries
      Section 5.7.  Case Study: Adding a New Wine
      Chapter 6.  Querying Web Databases
      Section 6.1.  Querying a MySQL Database Using PHP
      Section 6.2.  Processing User Input
      Section 6.3.  MySQL Function Reference
      Chapter 7.  PEAR
      Section 7.1.  Overview
      Section 7.2.  Core Components
      Section 7.3.  Packages
      Chapter 8.  Writing to Web Databases
      Section 8.1.  Database Inserts, Updates, and Deletes
      Section 8.2.  Issues in Writing Data to Databases
      Chapter 9.  Validation with PHP and JavaScript
      Section 9.1.  Validation and Error Reporting Principles
      Section 9.2.  Server-Side Validation with PHP
      Section 9.3.  JavaScript and Client-Side Validation
      Chapter 10.  Sessions
      Section 10.1.  Introducing Session Management
      Section 10.2.  PHP Session Management
      Section 10.3.  Case Study: Using Sessions in Validation
      Section 10.4.  When to Use Sessions
      Section 10.5.  PHP Session API and Configuration
      Chapter 11.  Authentication and Security
      Section 11.1.  HTTP Authentication
      Section 11.2.  HTTP Authentication with PHP
      Section 11.3.  Form-Based Authentication
      Section 11.4.  Protecting Data on the Web
      Chapter 12.  Errors, Debugging, and Deployment
      Section 12.1.  Errors
      Section 12.2.  Common Programming Errors
      Section 12.3.  Custom Error Handlers
      Chapter 13.  Reporting
      Section 13.1.  Creating a Report
      Section 13.2.  Producing PDF
      Section 13.3.  PDF-PHP Reference
      Chapter 14.  Advanced Features of Object-Oriented Programming in PHP 5
      Section 14.1.  Working with Class Hierarchies
      Section 14.2.  Class Type Hints
      Section 14.3.  Abstract Classes and Interfaces
      Section 14.4.  Freight Calculator Example
      Chapter 15.  Advanced SQL
      Section 15.1.  Exploring with SHOW
      Section 15.2.  Advanced Querying
      Section 15.3.  Manipulating Data and Databases
      Section 15.4.  Functions
      Section 15.5.  Automating Querying
      Section 15.6.  Table Types
      Section 15.7.  Backup and Recovery
      Section 15.8.  Managing Users and Privileges
      Section 15.9.  Tuning MySQL
      Chapter 16.  Hugh and Dave's Online Wines:A Case Study
      Section 16.1.  Functional and System Requirements
      Section 16.2.  Application Overview
      Section 16.3.  Common Components
      Chapter 17.  Managing Customers
      Section 17.1.  Code Overview
      Section 17.2.  Customer Validation
      Section 17.3.  The Customer Form
      Chapter 18.  The Shopping Cart
      Section 18.1.  Code Overview
      Section 18.2.  The Winestore Home Page
      Section 18.3.  The Shopping Cart Implementation
      Chapter 19.  Ordering and Shipping at the Online Winestore
      Section 19.1.  Code Overview
      Section 19.2.  Credit Card and Shipping Instructions
      Section 19.3.  Finalizing Orders
      Section 19.4.  HTML and Email Receipts
      Chapter 20.  Searching and Authentication in the Online Winestore
      Section 20.1.  Code Overview
      Section 20.2.  Searching and Browsing
      Section 20.3.  Authentication
      Appendix A.  Linux Installation Guide
      Section A.1.  Finding Out What's Installed
      Section A.2.  Installation Overview
      Section A.3.  Installing MySQL
      Section A.4.  Installing Apache
      Section A.5.  Installing PHP
      Section A.6.  What's Needed for This Book
      Appendix B.  Microsoft Windows Installation Guide
      Section B.1.  Installation Overview
      Section B.2.  Installing with EasyPHP
      Section B.3.  What's Needed for This Book
      Appendix C.  Mac OS X Installation Guide
      Section C.1.  Getting Started
      Section C.2.  Installing MySQL
      Section C.3.  Setting Up Apache and PHP
      Section C.4.  What's Needed for This Book
      Appendix D.  Web Protocols
      Section D.1.  Network Basics
      Section D.2.  Hypertext Transfer Protocol
      Appendix E.  Modeling and Designing Relational Databases
      Section E.1.  The Relational Model
      Section E.2.  Entity-Relationship Modeling
      Appendix F.  Managing Sessions in theDatabase Tier
      Section F.1.  Using a Database to Keep State
      Section F.2.  PHP Session Management
      Section F.3.  MySQL Session Store
      Appendix G.  Resources
      Section G.1.  Client Tier Resources
      Section G.2.  Middle-Tier Resources
      Section G.3.  Database Tier Resources
      Section G.4.  Security and Cryptography Resources
      Appendix H.  The Improved MySQL Library
      Section H.1.  New Features
      Section H.2.  Getting Started
      Section H.3.  Using the New Features
    Colophon
    Copyright



 

Previous Section  < Day Day Up >  Next Section

H.3 Using the New Features

This section explains some of the new features and illustrates them with short examples. We show you:

  • How to use the new basic features

  • Basic examples of how to prepare and execute statements

  • How to profile your MySQL function calls

We don't discuss features for working with replicated servers, the new transaction features, or how to set up compressed or encrypted connections

H.3.1 Basic Features

With the regular library, you connect to a server and select a database using a fragment such as the following:

$connection = mysql_connect("localhost", "fred", "shhh");

mysql_select_db("winestore", $connection);

With the improved library, you can combine these two steps as follows:

$connection = mysqli_connect("localhost", "fred", "shhh", "winestore");

As shown in Example H-2, you can still use the old approach if you want to.

Both the regular and improved libraries have two query functions. The regular library has mysql_query( ) and mysql_unbuffered_query( ), while the improved library has mysqli_query( ) and mysql_real_query( ). As we showed in the previous section, mysql_query( ) and mysqli_query( ) are equivalent.

The mysqli_real_query( ) function can be used for either buffered or unbuffered output; it can provide normal output or the same features as mysql_unbuffered_query( ). After you've called mysql_real_query( ), you need to call either mysql_use_result( ) or mysql_store_result( ) to specify how results are to be retrieved. If you call mysql_use_result( ), then rows are buffered on demand and the behavior is the same as mysql_unbuffered_query( ). If you call mysql_store_result( ), then all rows are buffered and the behavior is the same as mysql_query( ).

Consider an example that uses the regular library and mysql_query( ):

$result = mysql_query("SELECT * FROM customer", $connection);

This example runs the query and buffers all result rows. To do the same thing with the improved library, you can do either of the following:

// Simplified version

$result = mysqli_query($connection, "SELECT * FROM customer");



// Two-step version

if (mysqli_real_query($connection, "SELECT * FROM customer"))

  $result = mysqli_store_result($connection);

With the regular library, use mysql_unbuffered_query( ) as follows:

$result = mysql_unbuffered_query("SELECT * FROM customer", $connection);

To do the same thing with the improved library, do the following:

if (mysqli_real_query($connection, "SELECT * FROM customer"))

  $result = mysqli_use_result($connection);

If you prefer the object-oriented style of PEAR DB over the procedural style of the regular library, then you'll enjoy using the improved library. Here's an example fragment that uses the new object-oriented style:

<?php

$connection = mysqli_connect("localhost", "fred", "drum", "winestore");



$result = $connection->query("SELECT * FROM wine");



while ($row = $result->fetch_array( ))

{

  foreach($row as $element)

    print "$element ";

  print "\n";

}



$connection->close( );

?>

H.3.2 Preparing and Executing Queries

With the improved library, you can separate query preparation from query execution. This means that if you need to repeat the same query many times, but with different values, you can improve your application's performance.

To use this approach, write an SQL query that contains placeholders instead of values. Then issue a prepare statement that asks MySQL to do as much parsing and preparation of the statement as possible in advance. Then, repeatedly replace the placeholders with values and execute the prepared query.

H.3.2.1 Inserting data

Consider an example of inserting data with prepare and execute. Suppose you want to insert more than one row into the items table from the winestore database. The table was created with the following statement:

CREATE TABLE items (

  cust_id int(5) NOT NULL,

  order_id int(5) NOT NULL,

  item_id int(3) NOT NULL,

  wine_id int(4) NOT NULL,

  qty int(3),

  price decimal(5,2),

  PRIMARY KEY (cust_id,order_id,item_id)

) type=MyISAM;

Without prepare and execute, you'd insert two rows into the table using a fragment such as the following:

// first row to be inserted

$cust_id = 14;

$order_id = 3;

$item_id = 1;

$wine_id = 770;

$qty = 2;

$price = 16.95;



$result = mysqli_query($connection, 

  "INSERT INTO items VALUES ({$cust_id}, {$order_id}, {$item_id}, 

   {$wine_id}, {$qty}, {$price})");



if (mysqli_affected_rows($connection) != 1)

  die("Had a problem");



// Change the variables

$cust_id = 14;

$order_id = 3;

$item_id = 2;

$wine_id = 184;

$qty = 12;

$price = 12.90;



// Insert the second row

$result = mysqli_query($connection, 

  "INSERT INTO items VALUES ({$cust_id}, {$order_id}, {$item_id}, 

   {$wine_id}, {$qty}, {$price})");



if (mysqli_affected_rows($connection) != 1)

  die("Had a problem");

Using the prepare and execute approach, you insert the same rows using the following fragment:

// Create a query with placeholders

$query = "INSERT INTO items VALUES (?,?,?,?,?,?)";



// Prepare the query

$stmt = mysqli_prepare($connection, $query);



// first row to be inserted

$cust_id = 14;

$order_id = 3;

$item_id = 1;

$wine_id = 770;

$qty = 2;

$price = 16.95;



// Bind the variables to the placeholders

mysqli_bind_param($stmt,

  array(MYSQLI_BIND_INT, MYSQLI_BIND_INT, MYSQLI_BIND_INT,

        MYSQLI_BIND_INT, MYSQLI_BIND_INT, MYSQLI_BIND_DOUBLE),

  $cust_id, $order_id, $item_id, $wine_id, $qty, $price);



// Insert the first row

mysqli_execute($stmt);

if (mysqli_stmt_affected_rows($stmt) != 1)

  die("Had a problem");



// Change the variables

$cust_id = 14;

$order_id = 3;

$item_id = 2;

$wine_id = 184;

$qty = 12;

$price = 12.90;



// Insert the second row

mysqli_execute($stmt);

if (mysqli_stmt_affected_rows($stmt) != 1)

  die("Had a problem");



// Close the statement

mysqli_stmt_close($stmt);

This approach requires more steps, but it can tremendously improve performance when scaled up to large numbers of queries. The code just shown starts by creating and preparing a query with the following lines of code:

// Create a query with placeholders

$query = "INSERT INTO items VALUES (?,?,?,?,?,?)";



// Prepare the query

$stmt = mysqli_prepare($connection, $query);

The question mark characters ? represent where values will be placed when the query is executed. The mysqli_prepare( ) function returns a prepared query statement that's saved in the variable $stmt.

After you create variables and assign them the values to be inserted, you bind the variables to the placeholders in the prepared statement using the following fragment:

// Bind the variables to the placeholders

mysqli_bind_param($stmt,

  array(MYSQLI_BIND_INT, MYSQLI_BIND_INT, MYSQLI_BIND_INT,

        MYSQLI_BIND_INT, MYSQLI_BIND_INT, MYSQLI_BIND_DOUBLE),

  $cust_id, $order_id, $item_id, $wine_id, $qty, $price);

The first parameter is the prepared statement. The second parameter is an array that specifies the types of each of the variables that are bound to the statement. In this example, there are six variables, where the first five are integers and the last is a double precision number. You can also specify MYSQL_BIND_STRING to bind a string variable and MYSQL_SEND_DATA to bind a very large amount of data. The remaining parameters are the variables themselves, and they must match the elements in the second parameter, both in the number of elements and their order.

Once the variables are bound to the query, you can execute the statement. In the fragment, this is done with:

// Insert the first row

mysqli_execute($stmt);



if (mysqli_stmt_affected_rows($stmt) != 1)

  die("Had a problem");

The function mysqli_stmt_affected_rows( ) is the same as mysqli_affected_rows( ), but works for statements instead of regular queries.

Now that the query is prepared and the variables are bound, to insert another row, all you need to do is change the values of the variables and reexecute the statement:

// Change the variables

$cust_id = 14;

$order_id = 3;

$item_id = 2;

$wine_id = 184;

$qty = 12;

$price = 12.90;



// Insert the second row

mysqli_execute($stmt);



if (mysqli_stmt_affected_rows($stmt) != 1)

  die("Had a problem");

Once you've finished with a prepared statement, you can free the resources that are associated with it using:

// Close the statement

mysqli_stmt_close($stmt);

The code we've shown is somewhat artificial. Normally, you'd do the preparation and binding, and then run a loop that creates the input, assigns the values to the placeholders, and executes the query.

H.3.2.2 Retrieving data

You can also repeat a SELECT query using the prepare and execute approach. This is useful if you want to run the same query, but want to use different values each time in the WHERE clause. For example, this would be a useful tool in our online winestore search feature, where wine prices are repeatedly retrieved for different wines.

Let's start by showing the old way of doing things. Wine prices can be retrieved using the following function (which is based on the showPricing( ) function described in Chapter 16 but rewritten to use the improved MySQL library):

function showPricing($connection)

{

  global $wineID;



  // Find the price of the cheapest inventory

  $query = "SELECT min(cost) FROM inventory

             WHERE wine_id = {$wineID}";



   // Run the query

   $result = mysqli_query($connection, $query);



   // Retrieve and return the price

   $row = mysqli_fetch_array($result, MYSQLI_BOTH);



   return $row["min(cost)"];

}

To modify the function to use the prepare and execute approach, you need to have an extra variable that stores a prepared statement. If the statement isn't yet prepared, the function will prepare it. If it is prepared, then it'll use that statement. Here's the rewritten code:

function showPricing($connection)

{

  global $statement, $wineID;



   if (empty($statement))

   {

     // Find the price of the cheapest inventory

     $query = "SELECT min(cost) FROM inventory

               WHERE wine_id = ?";



      // Prepare the query

      $statement = mysqli_prepare($connection, $query);



      // Bind the $wineID to the placeholder

      mysqli_bind_param($statement, array(MYSQLI_BIND_INT), $wineID);

   }



   // Run the query

   mysqli_execute($statement);



   $cost = "";



   // Bind the output -- links min(cost) to $cost

   mysqli_bind_result($statement, $cost);



   // Retrieve and return the price

   mysqli_fetch($statement);



   return $cost;

}

The code is a little longer than the old way of doing things, but it's much faster when prices are retrieved many times. The following fragment checks if the statement has been prepared and, if not, it prepares it and binds the $wineID to the placeholder:

   if (empty($statement))

   {

     // Find the price of the cheapest inventory

     $query = "SELECT min(cost) FROM inventory

               WHERE wine_id = ?";



      // Prepare the query

      $statement = mysqli_prepare($connection, $query);



      // Bind the $wineID to the placeholder

      mysqli_bind_param($statement, array(MYSQLI_BIND_INT), $wineID);

   }

This process is explained in the previous section. However, in this example, we've declared the $wineID as global in the function; at the time of writing, passing the variable as a parameter by reference didn't work.

Once the statement is prepared, it is executed with:

   // Run the query

   mysqli_execute($statement);

Now that the query has been run, we need to retrieve the results. To do this, you need to bind the output to one or more variables. In our example, there's only one attribute retrieved by the query, min(cost). This is bound to the variable $cost using the following fragment:

   // Bind the output -- links min(cost) to $cost

   mysqli_bind_result($statement, $cost);

If there were instead two attributes returned by the query, you'd bind both using two variables:

   mysqli_bind_result($statement, $var1, $var2);

Once the variable has been bound to the output, you can retrieve the row of data and the value of $cost:

   // Retrieve and return the price

   mysqli_fetch($statement);



   return $cost;

Note that you must use mysqli_fetch( ) to retrieve rows from an executed query and that it takes the statement as its parameter.

H.3.3 Profiling Queries

The new query profiler allows you to collect information about how the improved MySQL library is functioning. Once configured, it reports information including:


Source file data

The name and line number of each improved MySQL function library call.


Timings

The total script execution time, and the execution time of each MySQL function call.


Parameters and warnings

Information such as the machine host name, database server user name, and warnings about missing statements (for example, warning you that you didn't call mysqli_close( )).


Query data

For each MySQL function call, the report lists information such as the function called, its return value, the query string passed as a parameter, the output of the EXPLAIN statement for that query (which shows how the query was evaluated), and the number of affected rows.

You can use this information to correct bugs and warnings and check the query speed (and take corrective action if it isn't acceptable). The information is output in an XML format.

To use the profiler, call the mysqli_profiler( ) function at the beginning of each script you want to profile. The easiest option is to write the report to a file. You can do this with:

mysqli_profiler(MYSQLI_PR_REPORT_FILE, "/tmp/report");

Replace /tmp/report with the directory and file you want to write the report to. You can also write to the stderr device on a Unix platform by using:

mysqli_profiler(MYSQLI_PR_REPORT_STDERR);

You can also write to a network socket, but we don't discuss this here.

In part, the output of a report has the following example format:

<query>

<functionname>mysqli_query</functionname>

<fileinfo>

<filename>/usr/local/apache2/htdocs/test.php</filename>

<line>7</line>

</fileinfo>

<timeinfo>

<execution_time>0.000636</execution_time>

</timeinfo>

<query_string>SELECT * FROM wine</query_string>

<explain>

<id>1</id>

<select_type>SIMPLE</select_type>

<table>wine</table>

<type>ALL</type>

<possible_keys>(null)</possible_keys>

<key>(null)</key>

<key_len>(null)</key_len>

<ref>(null)</ref>

<rows>1048</rows>

<Extra></Extra>

</explain>

<affected_rows>-1</affected_rows>

    Previous Section  < Day Day Up >  Next Section







    Copyright © 2010 | Domen maybe sale - bye this domen