© 2007 Oracle Corporation
© 2007 Oracle Corporation
© 2007 Oracle Corporation
The Way to the Web with PHP and Oracle DatabaseChristopher Jones, Product Development, OracleOracle Develop, November 2007
© 2007 Oracle Corporation
The following is intended to outline our general
product direction. It is intended for information
purposes only, and may not be incorporated into any
contract. It is not a commitment to deliver any
material, code, or functionality, and should not be
relied upon in making purchasing decisions.
The development, release, and timing of any
features or functionality described for Oracle’s
products remain at the sole discretion of Oracle.
© 2007 Oracle Corporation
Overview
• About PHP and Oracle
• Using PHP's OCI8 extension
• Maximizing OCI8 performance
• PHP Applications
© 2007 Oracle Corporation
OCI8 Extension
© 2007 Oracle Corporation
What is OCI8?
<?php
$c = oci_connect('un', 'pw', '//localhost/XE');
$s = oci_parse($c, 'select * from employees');
oci_execute($s);
while ($row = oci_fetch_array($s))
foreach ($row as $item)
print $item;
?>
• Main Oracle Database extension for PHP
• Open source and part of PHP
© 2007 Oracle Corporation
OCI8 Basic Oracle Features
• SQL and PL/SQL
• Long Objects (LOB), including Temporary LOBs
• Collections
• REFCURSORS
• Bind Data
• Change Password
• Privileged Connections
• Meta Data
© 2007 Oracle Corporation
OCI8 Performance Features
• Prefetch Rows
• Array Binds
• Statement Cache
• Fast Application Notification*
• With Oracle Database 11g• Server Result Cache
• Consistent Client Cache
• PL/SQL Function Cache
• Database Resident Connection Pooling*
* Support in PHP is currently Beta
© 2007 Oracle Corporation
Three Tier Web Model
Oracle Database8i, 9i, 10g, 11gAny platform
Web User Mid Tier9iR2, 10g, 11gAny platform
Apache
PHP
OCI8 ExtensionOracle Client Libraries
© 2007 Oracle Corporation
OCI8 Extension History
• Refactored by Oracle and Zend in 2005• Stable and fast
• In PHP 5.1.2+
• Same API as original OCI8 in PHP 3 and PHP 4
• New php.ini parameters for
• Persistent connection management
• Row prefetching
• Client side statement cache
• Enhanced OCI8 Beta released October 2007• Connection pooling support (DRCP)
• High availability support (FAN)
© 2007 Oracle Corporation
Get the Refactored OCI8
• php.net• Source code, Windows Binaries
• PECL - PHP Extension Community Library• Useful for updating PHP 4 with new OCI8
• Currently the only location of latest Beta OCI8
• oss.oracle.com/projects/php• RPMs for Linux with OCI8 and PDO_OCI
• Zend Core for Oracle• Linux, Solaris, Windows, AIX
• Support from Zend
© 2007 Oracle Corporation
Alternatives to OCI8
• ADOdb, PEAR MDB2, ...• Database Abstraction libraries
• Written in PHP: use OCI8 calls
• All have similar basic functionality
• PDO (PHP Data Objects) • Data Access Abstraction
• Common and DB-specific calls
• Separate PHP Extension written in C
• Attracting interest, but not yet fully featured/stable
© 2007 Oracle Corporation
OCI8 Examples
© 2007 Oracle Corporation
SQL Statement Execution
• Parse - oci_parse()
Prepares a statement for execution
• Bind - oci_bind_by_name()
Optionally binds variables in WHERE clause or to PL/SQL arguments
• Execute - oci_execute()
The Database executes the statement and buffers the results
• Fetch - oci_fetch_array()
Optionally retrieves results from the database
© 2007 Oracle Corporation
Query Example
<?php
$c = oci_connect('hr','hrpwd','//localhost/XE');
$s = oci_parse($c, 'select last_name from employees');
oci_execute($s);
while ($row = oci_fetch_array($s))
foreach ($row as $item)
print htmlentities($item).”<br>\n”;
?>
• Text file in $HOME/public_html/q.php
• Creates HTML page
© 2007 Oracle Corporation
Query Example
<?php
$c = oci_connect('hr','hrpwd','//localhost/XE');
$s = oci_parse($c,
'select last_name from employees');
oci_execute($s);
while ($row = oci_fetch_array($s))
foreach ($row as $item)
print htmlentities($item).”<br>\n”;
?>
© 2007 Oracle Corporation
Insert Example
<?php
$c = oci_connect('hr','hrpwd','//localhost/XE');
$s = oci_parse($c,
"insert into employees (last_name) values ('Jones')";
oci_execute($s);
?>
• Use single and double quotes carefully
• No output
© 2007 Oracle Corporation
Bind Variables
insert into tabvalues (:bv)
insert into tab values (:bv)
insert into tab values (:bv)
insert into tab values (:bv)
1: insert into tab values (:bv)
Database cacheIncreasesperformanceand security
© 2007 Oracle Corporation
No Bind Variables
insert into tabvalues (1)
insert into tabvalues (2)
insert into tab values (1)
insert into tab values (2)
1: insert into tab values (1) 2: insert into tab values (2)
Database cache
Poor useof cache
© 2007 Oracle Corporation
Binding
• Associates PHP variable $name with the placeholder :bv
<?php
$c = oci_connect('hr','hrpwd','//localhost/XE');
$s = oci_parse($c,
'insert into employees (last_name) values (:bv)');
$name = 'Jones';
oci_bind_by_name($s, ':bv', $name);
oci_execute($s);
?>
© 2007 Oracle Corporation
Calling a PL/SQL Procedure
<?php
$c = oci_connect('hr','hrpwd','//localhost/XE');
$s = oci_parse($c, "begin myproc(1, 'Jones'); end;");
oci_execute($s);
?>
• No PHP output (empty page)
© 2007 Oracle Corporation
Calling a PL/SQL Function
create or replace function
myfunc(p1 in number) return number as
begin
return 2 * p1;
end;
© 2007 Oracle Corporation
Calling a PL/SQL Function
<?php
$c = oci_connect('hr','hrpwd','//localhost/XE');
$s = oci_parse($c, 'begin :res := myfunc(1); end;');
oci_bind_by_name($s, ':res', $r, 10);
oci_execute($s);
print "Result is $r <br>\n";
?>
• Prints “Result is 2”
• Use a bind length for “out” bind return values
© 2007 Oracle Corporation
Commit Is Default
• By default oci_execute() commits
• Unnecessarily committing:• Breaks transactions
• Increases “round trips” to the database
• Increases database load
• String concatenation is insecure
$a = array('a','b','c','d');
foreach ($a as $v) {
$s = oci_parse($c,
"insert into mytab values ('".$v."')");
$r = oci_execute($s); // automatically commits
}
© 2007 Oracle Corporation
Using Transactions
$a = array('a','b','c','d');
$s = oci_parse($c, 'insert into mytab values (:bv)');
oci_bind_by_name($s, ':bv', $v);
foreach ($a as $v) {
oci_execute($s, OCI_DEFAULT); // Doesn't commit
}
oci_commit($c);
• OCI_DEFAULT is not the default in PHP!
• One parse, one commit
• No SQL Injection worry
© 2007 Oracle Corporation
Transactional Performance
• Representative sample for me
• Your results will vary
© 2007 Oracle Corporation
Connection Management
© 2007 Oracle Corporation
Connections
• Standard Connections$c = oci_connect($un, $pw, $db);
• Second oci_connect() returns same handle
• Automatically closed at script completion
• Can explicitly close
• Persistent Connections$c = oci_pconnect($un, $pw, $db);
• Second oci_pconnect() returns same handle
• Not automatically closed; cannot explicitly close
(Beta OCI8 does allow them to be released)
© 2007 Oracle Corporation
Persistent Connections Cached
user:db:charset:privilegehr:XE:ALU32UTF8:normalsystem:XE:ALU32UTF8:sysdba
Second request fast
oci_pconnect()
© 2007 Oracle Corporation
Persistent Connections
$c = oci_pconnect($un, $pw, $db);
• Fast for subsequent connections• But holds database resources when application idle
• Configurable in php.inioci8.max_persistent
oci8.persistent_timeout
oci8.ping_interval
© 2007 Oracle Corporation
Maximum Number of Persistent Connections
• php.ini:oci8.max_persistent = -1
• Number of connections cached by each Apache process
• Using -1 means no limit
• If limit is reached, connections will succeed but will be treated like oci_connect() calls.
© 2007 Oracle Corporation
Timeout for Unused Persistent Connections
• php.ini:oci8.persistent_timeout = -1
• Seconds an idle connection will be retained
• Using -1 means no timeout
© 2007 Oracle Corporation
Round Trips Between PHP and Oracle
Round Trip
Tuning goal: minimize round trips
© 2007 Oracle Corporation
Pinging for Closed Persistent Connections
• php.ini:oci8.ping_interval = 60
• Seconds that pass before oci_pconnect() connection is checked before being used
• New connection created if old one unavailable
• Generates “round trip” to DB
• For scalability, disable by setting to -1• Applications need to recover from errors anyway
• With new Beta OCI8 use FAN events instead
© 2007 Oracle Corporation
Closing Connections
• An oci_close() closes connections from oci_connect() and oci_new_connect() (and oci_pconnect() with latest OCI8 Beta)
• Unset related resources first $s = null;
oci_close($con);
• Closing is good in many circumstances, e.g.• Long running scripts with little DB interaction
• For connection pooling with latest OCI8 Beta
© 2007 Oracle Corporation
Database Resident Connection Pooling (DRCP)
• oci_connect() has performance overhead of connection creation/destroy
• oci_pconnect() has potential memory overhead of idle open connections
• PHP is multi-process; older pooling solutions are multi-threaded
• Oracle 11g introduces DRCP
• OCI8 1.3.0 Beta supports DRCP
© 2007 Oracle Corporation
Fast Application Notification
• High Availability feature for PHP with RAC or Data Guard with physical standby
• When DB node or network fails• Database generates FAN events
• PHP error returned without TCP timeout delay
• PHP application can reconnect to surviving instance
• OCI8 1.3.0 Beta supports FAN
© 2007 Oracle Corporation
Environment Setting
© 2007 Oracle Corporation
Pass the Character Set
$c = oci_pconnect($un, $pw, $db, 'ja16euc');
• Removes need for environment lookup
• Improves performance even for persistent connections
© 2007 Oracle Corporation
Connection Performance
• Representative sample for me
• Your results will vary
• Tune your SQL first
© 2007 Oracle Corporation
Optimize Environment Setting
• Could be improved
function my_connect($un, $pw, $db) {$c = oci_pconnect($un, $pw, $db);$s = oci_parse($c, "alter session set
nls_date_format='YYYY-MM-DD HH24:MI:SS'");oci_execute($s);return $c;
}
© 2007 Oracle Corporation
Environment Setting: Process Environment
• Set NLS_DATE_FORMAT before starting Apache:$ export NLS_DATE_FORMAT='YYYY-MM-DD HH24:MI:SS'
$ apachectl start
• PHP function now is:function my_connect($un, $pw, $db) {
$c = oci_pconnect($un, $pw, $db);
return $c;
}
• All users get same format
• Application now depends on environment
© 2007 Oracle Corporation
Environment Setting: Trigger
• Use a PL/SQL LOGON trigger
create or replace trigger my_set_date
after logon on database
begin
if (user = 'HR') then
execute immediate
'alter session set nls_date_format =
''YYYY-MM-DD HH24:MI:SS'' ';
end if;
end my_set_date;
© 2007 Oracle Corporation
Environment Setting: Trigger
• PHP Code is
function my_connect($un, $pw, $db) {
$c = oci_pconnect($un, $pw, $db);
return $c;
}
© 2007 Oracle Corporation
LOGON Trigger
• Fires only first time oci_pconnect() is called after Apache process starts• This is when the DB connection is created
• Subsequent oci_pconnect() calls get previously established connection from PHP cache• Trigger not executed
• Multiple SQL statements can be executed in the trigger• Reduces number of calls between PHP and DB
© 2007 Oracle Corporation
LOGON Trigger
• Measured PHP times, not DB load
• Representative results for me
• Your results will vary
© 2007 Oracle Corporation
Connections with Oracle RAC
• Tune auditing sequence generator
SQL> alter sequence sys.audses$ cache 10000;
• Reduces data transfers between nodes
• Also useful for non-RAC connection peaks
(RAC is “Real Application Clusters”)
© 2007 Oracle Corporation
Statement Tuning
© 2007 Oracle Corporation
OCI8 Row Prefetching
$s = oci_parse($c,
'select location_id, city from locations');
oci_execute($s);
oci_set_prefetch($s, 100);
while ($row = oci_fetch_array($s))
foreach ($row as $item)
print $item;
© 2007 Oracle Corporation
OCI8 Row Prefetching
Oracle Client Libraries
OCI8 Extension
1000, Roma
Database
1000, Roma1100, Venice1200, Tokyo. . .
PHP
Reduces round trips
oci_fetch_array()
Oracle Client Libraries
OCI8 Extension
1100, Venice 1000, Roma1100, Venice1200, Tokyo. . .
oci_fetch_array()
No DB access for next fetch
© 2007 Oracle Corporation
OCI8 Row Prefetching
• Set in the PHP script:
oci_set_prefetch($s, 100);
Or in php.inioci8.default_prefetch = 100
• Each database “round trip” prefetches lesser of:• 100 rows
• 100 * 1024 bytes
• Rows are cached internally by Oracle
• No need to change application
• No effect for REFCURSORS
© 2007 Oracle Corporation
OCI8 Row Prefetching
• Representative sample for me
• Your results will vary
© 2007 Oracle Corporation
Statement Caching: Client
select col from tab
select col from tab
select col from tab
“Use statement 1”
1: select col from tab
Database cache
1: select col from tab
Client cache
Less traffic and DB CPU
© 2007 Oracle Corporation
OCI8 Statement Cache
• php.inioci8.statement_cache_size = 20
• Unit is number of statements
• Client side cache of statements
• Moves cache management load from DB to PHP side
• Reduces net traffic and context switches
• Uses memory on PHP side for cached statement handles
• Uses memory on DB for per-session cursors
© 2007 Oracle Corporation
Limiting Data Transfers
• Don't fetch more data than necessary
• Use SQL to process data e.g. inline views, analytic functions, ...
• Oracle row limiting query is:
SELECT last_name FROM
(SELECT last_name,
ROW_NUMBER() OVER
(ORDER BY last_name) AS MYR
FROM employees)
WHERE MYR BETWEEN 11 and 20;
© 2007 Oracle Corporation
Bulk Inserts (PL/SQL Side)create or replace package mypkg as
type arrtype is table of varchar2(20)
index by pls_integer;
procedure myproc(p1 in arrtype);
end mypkg;
create or replace package body mypkg as
procedure myproc(p1 in arrtype) is
begin
forall i in indices of p1
insert into mytab values (p1(i));
end myproc;
end mypkg;
© 2007 Oracle Corporation
Bulk Inserts (PHP Code)
$a = array('a', 'b', 'c', 'd');
$s = oci_parse($c, 'begin mypkg.myproc(:c1); end;');
oci_bind_array_by_name($s, ":c1", $a,
count($a), -1, SQLT_CHR);
oci_execute($s);
• Just three OCI8 calls
© 2007 Oracle Corporation
Insert Performance
• Representative sample for me
• Your results will vary
© 2007 Oracle Corporation
PHP Deployment
© 2007 Oracle Corporation
Alternative PHP Cache - APC
• PHP is interpreted (and mostly not thread safe) • Each HTTP request reloads/parses scripts
• No data sharing between requests
• APC is a shared memory cache• Opcode cache for PHP scripts
• Can store user values
• Not distributed
• Opcode caches like APC are used by most sites
• Currently a PHP extension in PECL • Will be in PHP 6 by default
© 2007 Oracle Corporation
APC Opcode Cache
• Highly configurable e.g. php.ini settings• to minimize cache warm-up pains
• to filter which files are cached
• to not stat the file system for file updates
• to choose for type of locking
• and more
© 2007 Oracle Corporation
APC User values
$query = 'select * from employees';
$key = md5($query);
if (apc_fetch($key)) {return apc_fetch($key);
}else {$s = oci_parse($c, $query);oci_execute($s);oci_fetch_all($s, $res);$ser = serialize($res);apc_store($key, $ser);return $result;
}
© 2007 Oracle Corporation
Memcached
• Distributed object caching system
• Runs as a server
• PHP Memcache Extension provides interface• API is procedural or object style
© 2007 Oracle Corporation
PHP Memcache Extension
$memcache = new Memcache;$memcache->connect('memcache_host', 1111);
$query = 'select * from employees';$key = md5($query);if ($memcache->get($key)) {return $memcache->get($key);
}else {$c = oci_pconnect('hr', 'hrpwd', '//localhost/XE');$s = oci_parse($c, $query);oci_execute($s);oci_fetch_all($s, $res);$ser = serialize($res);$memcache->set($key, $ser, TRUE, 86400); // Store one dayreturn $result;
}
© 2007 Oracle Corporation
Oracle 11g Result Caches
• Oracle 11g has server and client result caches
• Caches are managed by Oracle• client cache is automatically invalidated by server changes
select /*+ result_cache */ * from employees
© 2007 Oracle Corporation
Rich Internet Applications with PHP
© 2007 Oracle Corporation
Rich Internet Applications
• Javascript libraries for RIAYahoo UI, Prototype/Scriptaculous, Dojo, ...
• Provide buttons, menus, calendars, sliders, ....
• Javascript libraries and CSS
• Not PHP• But PHP can generate HTML/Javascript content
• PHP can be target of XMLHttpRequest calls
• Tending to use JSON to transfer data to/from PHP
© 2007 Oracle Corporation
XMLHttpRequest<html>
<head>
<script type="text/javascript">
function makeRequest()
{
httpRequest = new XMLHttpRequest();
httpRequest.open('GET', 'http://localhost:8888/~cjones/ajax1.php?somestuff');
httpRequest.onreadystatechange = function()
{
if (httpRequest.readyState == 4) { alert(httpRequest.responseText); }
}
httpRequest.send(null);
}
</script>
</head>
<body onload="makeRequest()">
</body>
</html>
© 2007 Oracle Corporation
PHP Frameworks
© 2007 Oracle Corporation
PHP Frameworks
• Solar, CakePHP, Zend Framework, ...
• Provide standard way of building web applications and web services
• Allow rapid development• Scaffolding
• Are written in PHP
• Functionality includes• MVC, ActiveRecord, ACLs, helpers for AJAX, data
sanitization, request handling, ...
• DB support varies
© 2007 Oracle Corporation
Other PHP Sessions
• Scale Your PHP Application to Tens of Thousands of Connections• Connection Pooling, High Availability, Oracle Database 11g
Caching
• 1:45pm - 2:45pm, Hilton Continental Parlor 7 & 8
• Web 2.0 Applications Hands-on Lab with PHP and Oracle Database• Try PHP out yourself
• 1:45pm - 2:45pm, Hilton Continental Ballroom 4
© 2007 Oracle Corporation
The preceding is intended to outline our general
product direction. It is intended for information
purposes only, and may not be incorporated into any
contract. It is not a commitment to deliver any
material, code, or functionality, and should not be
relied upon in making purchasing decisions.
The development, release, and timing of any
features or functionality described for Oracle’s
products remain at the sole discretion of Oracle.
© 2007 Oracle Corporation
Oracle Technology Network PHP Developer Center
• Articles
• Install guides
• Underground PHP and Oracle Manual
• Online forum
• PHP RPMs
• Oracle JDeveloper 10g PHP extension
oracle.com/technology/php
© 2007 Oracle Corporation
Oracle Resources
• Oracle Techology Network (OTN) is freePHP Developer Center
www.oracle.com/technology/php
• Underground PHP and Oracle Manual• Articles, FAQs, links to blogs, JDeveloper PHP Extension,
PHP RPMs
• SQL and PL/SQL Questionsasktom.oracle.com
blogs.oracle.com/opal
• ISVs and hardware vendorsoraclepartnernetwork oracle com
© 2007 Oracle Corporation