TeraWurflDatabase
[ class tree: TeraWurflDatabase ] [ index: TeraWurflDatabase ] [ all elements ]

Source for file TeraWurflDatabase_MSSQL2005.php

Documentation is available at TeraWurflDatabase_MSSQL2005.php

  1. <?php
  2. /**
  3.  * Tera_WURFL - PHP MySQL driven WURFL
  4.  * 
  5.  * Tera-WURFL was written by Steve Kamerman, and is based on the
  6.  * Java WURFL Evolution package by Luca Passani and WURFL PHP Tools by Andrea Trassati.
  7.  * This version uses a MySQL database to store the entire WURFL file, multiple patch
  8.  * files, and a persistent caching mechanism to provide extreme performance increases.
  9.  * 
  10.  * @package TeraWurflDatabase
  11.  * @author Steve Kamerman <stevekamerman AT gmail.com>
  12.  * @version Stable 2.1.3 $Date: 2010/09/18 15:43:21
  13.  * @license http://www.mozilla.org/MPL/ MPL Vesion 1.1
  14.  */
  15. /**
  16.  * Provides connectivity from Tera-WURFL to Microsoft SQL Server 2005/2008
  17.  * @package TeraWurflDatabase
  18.  */
  19.     
  20.     // Properties
  21.     public $errors;
  22.     // If you enable this, the RIS function will be performed on the SQL server, HOWEVER,
  23.     //   this is currently MUCH slower (~ x5 slower) than performing this function in PHP
  24.     public $db_implements_ris = false;
  25.     public $db_implements_ld = false;
  26.     public $numQueries = 0;
  27.     public $connected = false;
  28.     
  29.     protected $dbcon;
  30.     
  31.     public $maxquerysize = 0;
  32.     /**
  33.      * The maximum number of new rows that the database can handle in one INSERT statement
  34.      * @var unknown_type 
  35.      */
  36.     protected static $DB_MAX_INSERTS 500;
  37.     
  38.     public function __construct(){
  39.         parent::__construct();
  40.     }
  41.     
  42.     // Device Table Functions (device,hybrid,patch)
  43.     public function getDeviceFromID($wurflID){
  44.         $this->numQueries++;
  45.         $res sqlsrv_query($this->dbcon,"SELECT * FROM ".TeraWurflConfig::$TABLE_PREFIX.'Merge'." WHERE deviceID=".$this->SQLPrep($wurflID)) or die($this->lastDBError());
  46.         if(!sqlsrv_has_rows($res)){
  47.             sqlsrv_free_stmt($res);
  48.             throw new Exception("Tried to lookup an invalid WURFL Device ID: $wurflID");
  49.         }
  50.         $data sqlsrv_fetch_array($res);
  51.         sqlsrv_free_stmt($res);
  52.         return unserialize($data['capabilities']);
  53.     }
  54.     public function getActualDeviceAncestor($wurflID){
  55.         if($wurflID == "" || $wurflID == WurflConstants::$GENERIC)
  56.             return WurflConstants::$GENERIC;
  57.         $device $this->getDeviceFromID($wurflID);
  58.         if($device['actual_device_root']){
  59.             return $device['id'];
  60.         }else{
  61.             return $this->getActualDeviceAncestor($device['fall_back']);
  62.         }
  63.     }
  64.     public function getFullDeviceList($tablename){
  65.         $this->numQueries++;
  66.         $res sqlsrv_query($this->dbcon,"SELECT deviceID, user_agent FROM $tablename");
  67.         $data array();
  68.         if(!sqlsrv_has_rows($res)){
  69.             sqlsrv_free_stmt($res);
  70.             return $data;
  71.         }
  72.         while($row sqlsrv_fetch_array($res)){
  73.             $data[$row['deviceID']]=$row['user_agent'];
  74.         }
  75.         sqlsrv_free_stmt($res);
  76.         return $data;
  77.     }
  78.     // Exact Match
  79.     public function getDeviceFromUA($userAgent){
  80.         $this->numQueries++;
  81.         $query "SELECT deviceID FROM ".TeraWurflConfig::$TABLE_PREFIX.'Merge'." WHERE user_agent=".$this->SQLPrep($userAgent);
  82.         $res sqlsrv_query($this->dbcon,$query);
  83.         if(!sqlsrv_has_rows($res)){
  84.             sqlsrv_free_stmt($res);
  85.             return false;
  86.         }
  87.         $data sqlsrv_fetch_array($res);
  88.         sqlsrv_free_stmt($res);        
  89.         return $data['deviceID'];
  90.     }
  91.     // RIS == Reduction in String (reduce string one char at a time)
  92.     public function getDeviceFromUA_RIS($userAgent,$tolerance,UserAgentMatcher &$matcher){
  93.         $this->numQueries++;
  94.         $query sprintf("EXEC ".TeraWurflConfig::$TABLE_PREFIX."_RIS %s,%s,%s",$this->SQLPrep($userAgent),$tolerance,$this->SQLPrep($matcher->tableSuffix()));
  95.         $result sqlsrv_query($this->dbcon,$query);
  96.         if(!$result){
  97.             throw new Exception(sprintf("Error in DB RIS Query: %s. \nQuery: %s\n",$this->lastDBError(),$query));
  98.             exit();
  99.         }
  100.         $data sqlsrv_fetch_array($result);
  101.         sqlsrv_free_stmt($result);
  102.         $wurflid $data['DeviceID'];
  103.         return ($wurflid == 'NULL' || is_null($wurflid))WurflConstants::$GENERIC$wurflid;
  104.     }
  105.     // TODO: Implement with Stored Proc
  106.     // LD == Levesthein Distance
  107.     public function getDeviceFromUA_LD($userAgent,$tolerance,UserAgentMatcher &$matcher){
  108.         throw new Exception("Error: this function (LD) is not yet implemented in MySQL");die();
  109.         $safe_ua $this->SQLPrep($userAgent);
  110.         $this->numQueries++;
  111.         //$res = sqlsrv_query($this->dbcon,"call TeraWurfl_LD($safe_ua,$tolerance)");
  112.         // TODO: check for false
  113.         $data array();
  114.         while($row sqlsrv_fetch_array($res)){
  115.             $data[]=$row;
  116.         }
  117.         sqlsrv_free_stmt($res);
  118.         return $data;
  119.     }
  120.     public function loadDevices(&$tables){
  121.         $insert_errors array();
  122.         $insertcache array();
  123.         $insertedrows 0;
  124.         $this->createIndexTable();
  125.         $this->createSettingsTable();
  126.         $this->clearMatcherTables();
  127.         $this->createProcedures();
  128.         foreach($tables as $table => $devices){
  129.             // insert records into a new temp table until we know everything is OK
  130.             $temptable $table (self::$DB_TEMP_EXT);
  131.             $parts explode('_',$table);
  132.             $matcher array_pop($parts);
  133.             $this->createGenericDeviceTable($temptable);
  134.             foreach($devices as $device){
  135.                 sqlsrv_query($this->dbcon,"INSERT INTO ".TeraWurflConfig::$TABLE_PREFIX.'Index'." (deviceID,matcher) VALUES (".$this->SQLPrep($device['id']).",".$this->SQLPrep($matcher).")");
  136.                 // convert device root to tinyint format (0|1) for db
  137.                 if(strlen($device['user_agent']255){
  138.                     $insert_errors["Warning: user agent too long: \"".($device['id']).'"';
  139.                 }
  140.                 $insertcache[sprintf("SELECT %s,%s,%s,%s,%s \n",
  141.                     $this->SQLPrep($device['id']),
  142.                     $this->SQLPrep($device['user_agent']),
  143.                     $this->SQLPrep($device['fall_back']),
  144.                     $this->SQLPrep((isset($device['actual_device_root']))?$device['actual_device_root']:''),
  145.                     $this->SQLPrep(serialize($device))
  146.                 );
  147.                 // This batch of records is ready to be inserted
  148.                 if(count($insertcache>= self::$DB_MAX_INSERTS){
  149.                     $query "INSERT INTO $temptable (deviceID, user_agent, fall_back, actual_device_root, capabilities) ".implode(" UNION ALL ",$insertcache);
  150.                     $res sqlsrv_query($this->dbcon,$queryor $insert_errors["DB server reported error on id \"".$device['id']."\": ".$this->lastDBError();
  151.                     $insertedrows += sqlsrv_rows_affected($res);
  152.                     sqlsrv_free_stmt($res);
  153.                     $insertcache array();
  154.                     $this->numQueries++;
  155.                     $this->maxquerysize = (strlen($query)>$this->maxquerysize)strlen($query)$this->maxquerysize;
  156.                 }
  157.             }
  158.             // some records are probably left in the insertcache
  159.             if(count($insertcache0){
  160.                 $query "INSERT INTO $temptable (deviceID, user_agent, fall_back, actual_device_root, capabilities) ".implode(" UNION ALL ",$insertcache);
  161.                     $res sqlsrv_query($this->dbcon,$queryor $insert_errors["DB server reported error on id \"".$device['id']."\": ".$this->lastDBError();
  162.                     $insertedrows += sqlsrv_rows_affected($res);
  163.                     sqlsrv_free_stmt($res);
  164.                     $insertcache array();
  165.                     $this->numQueries++;
  166.                     $this->maxquerysize = (strlen($query)>$this->maxquerysize)strlen($query)$this->maxquerysize;
  167.             }
  168.             if(count($insert_errors0){
  169.                 // Roll back changes
  170.                 // leave the temp table in the DB for manual inspection
  171.                 $this->errors = array_merge($this->errors,$insert_errors);
  172.                 return false;
  173.             }
  174.             $this->numQueries++;
  175.             $this->dropTableIfExists($table);
  176.             $this->numQueries++;
  177.             $this->renameTable($temptable,$table);
  178.         }
  179.         // Create Merge Table
  180.         $this->createMergeTable(array_keys($tables));
  181.         return true;
  182.     }
  183.     /**
  184.      * Drops and creates the given device table
  185.      *
  186.      * @param string Table name (ex: TeraWurflConfig::$HYBRID)
  187.      * @return boolean success
  188.      */
  189.     public function createGenericDeviceTable($tablename){
  190.         $createtable "CREATE TABLE [dbo].[{$tablename}](
  191.     [deviceID] [nvarchar](128) NOT NULL,
  192.     [user_agent] [nvarchar](255) NULL,
  193.     [fall_back] [nvarchar](128) NULL,
  194.     [match] [tinyint] NULL,
  195.     [actual_device_root] [tinyint] NULL,
  196.     [capabilities] [ntext] NULL,
  197.  CONSTRAINT [PK_{$tablename}] PRIMARY KEY CLUSTERED 
  198. (
  199.     [deviceID] ASC
  200. )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
  201. ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]";
  202.         $createkeys "ALTER TABLE [dbo].[{$tablename}] ADD CONSTRAINT [DF_{$tablename}_actual_device_root]  DEFAULT ((0)) FOR [actual_device_root]
  203. CREATE NONCLUSTERED INDEX [IDX_{$tablename}_fall_back] ON [dbo].[{$tablename}] ([fall_back])
  204. CREATE NONCLUSTERED INDEX [IDX_{$tablename}_user_agent] ON [dbo].[{$tablename}] ([user_agent])
  205. CREATE NONCLUSTERED INDEX [IDX_{$tablename}_match] ON [dbo].[{$tablename}] ([match])";
  206.         $this->numQueries++;
  207.         $this->dropTableIfExists($tablename);
  208.         $this->numQueries++;
  209.         sqlsrv_query($this->dbcon,$createtable);
  210.         $this->numQueries++;
  211.         sqlsrv_query($this->dbcon,$createkeys);
  212.         return true;
  213.     }
  214.     /**
  215.      * Drops then creates all the UserAgentMatcher device tables
  216.      * @return boolean success
  217.      */
  218.     protected function clearMatcherTables(){
  219.         foreach(UserAgentFactory::$matchers as $matcher){
  220.             $table TeraWurflConfig::$TABLE_PREFIX."_".$matcher;
  221.             $this->createGenericDeviceTable($table);
  222.         }
  223.         return true;
  224.     }
  225.     /**
  226.      * Drops and creates the MERGE table
  227.      *
  228.      * @param array Table names
  229.      * @return boolean success
  230.      */
  231.     public function createMergeTable($tables){
  232.         $tablename TeraWurflConfig::$TABLE_PREFIX.'Merge';
  233.         foreach($tables as &$table){$table="SELECT * FROM $table";}
  234.         $this->createGenericDeviceTable($tablename);
  235.         $createtable "INSERT INTO $tablename ".implode(" UNION ALL ",$tables);
  236.         $this->numQueries++;
  237.         sqlsrv_query($this->dbcon,$createtableor die("ERROR: ".$this->lastDBError());
  238.         return true;
  239.     }
  240.     /**
  241.      * Drops and creates the index table
  242.      *
  243.      * @return boolean success
  244.      */
  245.     public function createIndexTable(){
  246.         $tablename TeraWurflConfig::$TABLE_PREFIX.'Index';
  247.         $createtable "CREATE TABLE [dbo].[$tablename](
  248.     [deviceID] [nvarchar](128) NOT NULL,
  249.     [matcher] [nvarchar](64) NOT NULL,
  250.  CONSTRAINT [PK_{$tablename}] PRIMARY KEY CLUSTERED 
  251. (
  252.     [deviceID] ASC
  253. )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
  254. ) ON [PRIMARY]";
  255.         $this->numQueries++;
  256.         $this->dropTableIfExists($tablename);
  257.         $this->numQueries++;
  258.         sqlsrv_query($this->dbcon,$createtable);
  259.         return true;
  260.     }
  261.     /**
  262.      * Creates the settings table if it does not already exist
  263.      * @return boolean success
  264.      */
  265.     public function createSettingsTable(){
  266.         $tablename TeraWurflConfig::$TABLE_PREFIX.'Settings';
  267.         $catalog TeraWurflConfig::$DB_SCHEMA;
  268.         $checktable "SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_CATALOG = '$catalog' AND TABLE_NAME = '$tablename'";
  269.         $this->numQueries++;
  270.         $res sqlsrv_query($this->dbcon,$checktableor die(print_r(sqlsrv_errors(SQLSRV_ERR_ERRORS)));
  271.         if(sqlsrv_has_rows($res)) return true;
  272.         sqlsrv_free_stmt($res);
  273.         $createtable "CREATE TABLE [dbo].[$tablename](
  274.     [id] [nvarchar](64) NOT NULL,
  275.     [value] [nvarchar](255) NULL,
  276.  CONSTRAINT [PK_{$tablename}] PRIMARY KEY CLUSTERED
  277. (
  278.     [id] ASC
  279. )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
  280. ) ON [PRIMARY]";
  281.         $this->numQueries++;
  282.         sqlsrv_query($this->dbcon,$createtable);
  283.         return true;
  284.     }
  285.     // Cache Table Functions
  286.     
  287.     // should return (bool)false or the device array
  288.     public function getDeviceFromCache($userAgent){
  289.         $tablename TeraWurflConfig::$TABLE_PREFIX.'Cache';
  290.         $this->numQueries++;
  291.         $res sqlsrv_query($this->dbcon,"SELECT * FROM $tablename WHERE user_agent=".$this->SQLPrep($userAgent)) or die("Error: ".$this->lastDBError());
  292.         if(!sqlsrv_has_rows($res)){
  293.             sqlsrv_free_stmt($res);
  294.             //echo "[[UA NOT FOUND IN CACHE: $userAgent]]";
  295.             return false;
  296.         }
  297.         $data sqlsrv_fetch_array($res);
  298.         sqlsrv_free_stmt($res);
  299.         return unserialize($data['cache_data']);
  300.         
  301.     }
  302.     public function saveDeviceInCache($userAgent,$device){
  303.         $tablename TeraWurflConfig::$TABLE_PREFIX.'Cache';
  304.         $ua $this->SQLPrep($userAgent);
  305.         $packed_device $this->SQLPrep(serialize($device));
  306.         $this->numQueries++;
  307.         $res sqlsrv_query($this->dbcon,"INSERT INTO $tablename (user_agent,cache_data) VALUES ($ua,$packed_device)");
  308.         if(sqlsrv_rows_affected($res0){
  309.             sqlsrv_free_stmt($res);
  310.             return true;
  311.         }
  312.         sqlsrv_free_stmt($res);
  313.         return false;
  314.     }
  315.     public function createCacheTable(){
  316.         return $this->createGenericCacheTable(TeraWurflConfig::$TABLE_PREFIX.'Cache');
  317.     }
  318.     public function createTempCacheTable(){
  319.         return $this->createGenericCacheTable(TeraWurflConfig::$TABLE_PREFIX.'Cache'.self::$DB_TEMP_EXT);
  320.     }
  321.     protected function createGenericCacheTable($tablename){
  322.         $createtable "CREATE TABLE [dbo].[{$tablename}](
  323.     [user_agent] [nvarchar](255) NOT NULL,
  324.     [cache_data] [ntext] NOT NULL,
  325.  CONSTRAINT [PK_{$tablename}] PRIMARY KEY CLUSTERED 
  326. ([user_agent] ASC)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
  327. ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]";
  328.         $this->numQueries++;
  329.         $this->dropTableIfExists($tablename);
  330.         $this->numQueries++;
  331.         $test sqlsrv_query($this->dbcon,$createtable);
  332.         return true;
  333.     
  334.     public function rebuildCacheTable(){
  335.         // We'll use this instance to rebuild the cache and to facilitate logging
  336.         $rebuilder new TeraWurfl();
  337.         $cachetable TeraWurflConfig::$TABLE_PREFIX.'Cache';
  338.         $temptable TeraWurflConfig::$TABLE_PREFIX.'Cache'.self::$DB_TEMP_EXT;
  339.         $this->numQueries++;
  340.         if(!$this->tableExists($cachetable)){
  341.             // This can only happen if the table doesn't exist
  342.             $this->createCacheTable();
  343.             $this->numQueries++;
  344.             // This table must be empty, so we're finished
  345.             $rebuilder->toLog("Created empty cache table",LOG_NOTICE,"rebuildCacheTable");
  346.             return true;
  347.         }
  348.         $this->numQueries++;
  349.         $this->dropTableIfExists($temptable);
  350.         $this->renameTable($cachetable,$temptable);
  351.         $this->numQueries++;
  352.         $this->createCacheTable();
  353.         $query "SELECT user_agent FROM $temptable";
  354.         $this->numQueries++;
  355.         $res sqlsrv_query($this->dbcon,$query);
  356.         if(!sqlsrv_has_rows($res)){
  357.             // No records in cache table == nothing to rebuild
  358.             $rebuilder->toLog("Rebuilt cache table, existing table was empty.",LOG_WARNING,"rebuildCacheTable");
  359.             return true;
  360.         }
  361.         while($dev sqlsrv_fetch_array($res)){
  362.             // Just looking the device up will force it to be cached
  363.             $rebuilder->GetDeviceCapabilitiesFromAgent($dev['user_agent']);
  364.             // Reset the number of queries since we're not going to re-instantiate the object
  365.             $this->numQueries += $rebuilder->db->numQueries;
  366.             $rebuilder->db->numQueries 0;
  367.         }
  368.         $this->numQueries++;
  369.         $this->dropTableIfExists($temptable);
  370.         $rebuilder->toLog("Rebuilt cache table.",LOG_NOTICE,"rebuildCacheTable");
  371.         return true;
  372.     }
  373.     // Supporting DB Functions
  374.     
  375.     // truncate or drop+create given table
  376.     public function clearTable($tablename){
  377.         if($tablename == TeraWurflConfig::$TABLE_PREFIX.'Cache'){
  378.             $this->createCacheTable();
  379.         }else{
  380.             $this->createGenericDeviceTable($tablename);
  381.         }
  382.     }
  383.     public function createProcedures(){
  384.         $TeraWurfl_RIS "CREATE PROCEDURE [dbo].[".TeraWurflConfig::$TABLE_PREFIX."_RIS] 
  385.     @ua nvarchar(255),
  386.     @tolerance int,
  387.     @matcher nvarchar(64)
  388. AS
  389. BEGIN
  390. SET NOCOUNT ON;
  391.  
  392. DECLARE @curlen int
  393. DECLARE @wurflid nvarchar(128)
  394. DECLARE @curua nvarchar(255)
  395.  
  396. SET @wurflid = NULL
  397. SET @curlen = LEN(@ua)
  398.  
  399. WHILE @curlen >= @tolerance
  400. BEGIN
  401.     SET @curua = dbo.".TeraWurflConfig::$TABLE_PREFIX."_EscapeForLike(LEFT(@ua, @curlen))+'%'
  402.     SELECT TOP 1 @wurflid=idx.DeviceID
  403.         FROM ".TeraWurflConfig::$TABLE_PREFIX.'Index'." idx INNER JOIN ".TeraWurflConfig::$TABLE_PREFIX.'Merge'." mrg ON idx.DeviceID = mrg.DeviceID
  404.         WHERE idx.matcher = @matcher
  405.         AND mrg.user_agent LIKE @curua
  406.     IF @wurflid IS NOT NULL BREAK
  407.     SET @curlen = @curlen - 1
  408. END
  409.  
  410. SELECT @wurflid as DeviceID
  411.  
  412. END";
  413.         $TeraWurfl_EscapeForLike "CREATE FUNCTION ".TeraWurflConfig::$TABLE_PREFIX."_EscapeForLike 
  414. (
  415.     @value nvarchar(300)
  416. )
  417. RETURNS nvarchar(300)
  418. AS
  419. BEGIN
  420.     SET @value = REPLACE(@value,'[','[[]');
  421.     SET @value = REPLACE(@value,'%','[%]');
  422.     SET @value = REPLACE(@value,'_','[_]');
  423.     RETURN @value
  424. END";
  425.         if($this->procedureExists(TeraWurflConfig::$TABLE_PREFIX.'_RIS')){sqlsrv_query($this->dbcon,"DROP PROCEDURE ".TeraWurflConfig::$TABLE_PREFIX."_RIS");}
  426.         sqlsrv_query($this->dbcon,$TeraWurfl_RIS);
  427.         if($this->functionExists(TeraWurflConfig::$TABLE_PREFIX.'_EscapeForLike')){sqlsrv_query($this->dbcon,"DROP PROCEDURE ".TeraWurflConfig::$TABLE_PREFIX."_EscapeForLike");}
  428.         sqlsrv_query($this->dbcon,$TeraWurfl_EscapeForLike);
  429.         return true;
  430.     }
  431.     /**
  432.      * Establishes connection to database (does not check for DB sanity)
  433.      */
  434.     public function connect(){
  435.         $this->numQueries++;
  436.         $connectionInfo array(
  437.             "UID"=>TeraWurflConfig::$DB_USER,
  438.             "PWD"=>TeraWurflConfig::$DB_PASS,
  439.             "Database"=>TeraWurflConfig::$DB_SCHEMA
  440.         );
  441.         /* Connect using SQL Server Authentication. */
  442.         $this->dbcon = sqlsrv_connectTeraWurflConfig::$DB_HOST$connectionInfo);
  443.         if($this->dbcon === false){
  444.             $error_array sqlsrv_errors(SQLSRV_ERR_ALL);
  445.             foreach($error_array as $err){$this->errors[]=$err['message'];}
  446.             $this->connected = false;
  447.             return false;
  448.         }
  449.         $this->connected = true;
  450.         return true;
  451.     }
  452.     public function updateSetting($key,$value){
  453.         $tablename TeraWurflConfig::$TABLE_PREFIX.'Settings';
  454.         $deletequery sprintf("DELETE FROM %s WHERE %s = %s"$tablename'id'$this->SQLPrep($key));
  455.         $this->numQueries++;
  456.         sqlsrv_query($this->dbcon,$deletequery);
  457.         $query sprintf("INSERT INTO %s ([%s], [%s]) VALUES (%s, %s)"$tablename'id''value'$this->SQLPrep($key)$this->SQLPrep($value));
  458.         $this->numQueries++;
  459.         sqlsrv_query($this->dbcon,$query);
  460.     }
  461.     public function getSetting($key){
  462.         $query "SELECT [value] FROM ".TeraWurflConfig::$TABLE_PREFIX.'Settings'." WHERE [id] = ".$this->SQLPrep($key);
  463.         $this->numQueries++;
  464.         $res sqlsrv_query($this->dbcon,$query);
  465.         if(!sqlsrv_has_rows($res)) return null;
  466.         $row sqlsrv_fetch_array($res);
  467.         sqlsrv_free_stmt($res);
  468.         return $row['value'];
  469.     }
  470.     // prep raw text for use in queries (adding quotes if necessary)
  471.     public function SQLPrep($value){
  472.         if($value == ''$value 'NULL';
  473.         else if (!is_numeric($value|| $value[0== '0'$value "'" str_replace("'","''",$value"'"//Quote if not integer
  474.         return $value;
  475.     }
  476.     protected function SQLEscapeForLike($value){
  477.         // http://msdn.microsoft.com/en-us/library/ms179859.aspx
  478.         $value str_replace('[','[[]',$value);
  479.         $value str_replace('%','[%]',$value);
  480.         $value str_replace('_','[_]',$value);
  481.         return $value;
  482.     }
  483.     public function getTableList(){
  484.         $tableres sqlsrv_query($this->dbcon,"SELECT TABLE_NAME FROM information_schema.tables WHERE Table_Type = 'BASE TABLE'");
  485.         $tables array();
  486.         while($table sqlsrv_fetch_array($tableres,SQLSRV_FETCH_NUMERIC))$tables[]=$table[0];
  487.         sqlsrv_free_stmt($tableres);
  488.         return $tables;
  489.     }
  490.     public function getMatcherTableList(){
  491.         $tableres sqlsrv_query($this->dbcon,"SELECT TABLE_NAME FROM information_schema.tables WHERE Table_Type = 'BASE TABLE' AND TABLE_NAME LIKE ".$this->SQLPrep($this->SQLEscapeForLike(TeraWurflConfig::$TABLE_PREFIX.'_').'%'));
  492.         $tables array();
  493.         while($table sqlsrv_fetch_array($tableres,SQLSRV_FETCH_NUMERIC))$tables[]=$table[0];
  494.         sqlsrv_free_stmt($tableres);
  495.         return $tables;
  496.     }
  497.     protected function tableExists($tablename){
  498.         $tableres sqlsrv_query($this->dbcon,"SELECT COUNT(1) FROM information_schema.tables WHERE Table_Type = 'BASE TABLE' AND TABLE_NAME = ".$this->SQLPrep($tablename));
  499.         $row sqlsrv_fetch_array($tableres);
  500.         sqlsrv_free_stmt($tableres);
  501.         return ($row[0]>0)truefalse;
  502.     }
  503.     protected function functionExists($func){
  504.         $query "SELECT COUNT(1) FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[{$func}]') AND type in (N'FN', N'IF', N'TF', N'FS', N'FT')";
  505.         $res sqlsrv_query($this->dbcon,$query);
  506.         $row sqlsrv_fetch_array($res);
  507.         return ($row[0]>0)truefalse;
  508.     }
  509.     protected function procedureExists($proc){
  510.         $query "SELECT COUNT(1) FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[{$proc}]') AND type in (N'P', N'PC')";
  511.         $res sqlsrv_query($this->dbcon,$query);
  512.         $row sqlsrv_fetch_array($res);
  513.         return ($row[0]>0)truefalse;
  514.     }
  515.     protected function dropTableIfExists($tablename){
  516.         if(!$this->tableExists($tablename)) return true;
  517.         $res sqlsrv_query($this->dbcon,"DROP TABLE $tablename");
  518.         sqlsrv_free_stmt($res);
  519.         return true;
  520.     }
  521.     protected function renameTable($from,$to){
  522.         // Rename the table
  523.         $query "exec sp_rename '$from', '$to'";
  524.         sqlsrv_query($this->dbcon,$query);
  525.         // Rename the primary key to avoid constraint / index name collision
  526.         $keyfrom $to.'.PK_'.$from;
  527.         $keyto 'PK_'.$to;
  528.         $query "exec sp_rename '$keyfrom', '$keyto', 'INDEX'";
  529.         sqlsrv_query($this->dbcon,$query);
  530.         return true;
  531.     }
  532.     //TODO: MSSQL
  533.     public function getTableStats($table){
  534.         $stats array();
  535.         $query "SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.Columns where TABLE_CATALOG = '".TeraWurflConfig::$DB_SCHEMA."' AND TABLE_NAME = '$table'";
  536.         $fieldsres sqlsrv_query($this->dbcon,$query);
  537.         while($row sqlsrv_fetch_array($fieldsres)){
  538.             $fieldnames[]=$row['COLUMN_NAME'];
  539.         }
  540.         sqlsrv_free_stmt($fieldsres);
  541.         $query "exec sp_spaceused '$table'";
  542.         $res sqlsrv_query($this->dbcon,$query);
  543.         $row sqlsrv_fetch_array($res);
  544.         $stats['rows'$row['rows'];
  545.         $stats['bytesize'intval($row['data']1024;
  546.         sqlsrv_free_stmt($res);
  547.         if(in_array("actual_device_root",$fieldnames)){
  548.             $res sqlsrv_query($this->dbcon,"SELECT COUNT(1) AS devcount FROM $table WHERE actual_device_root=1");
  549.             $row sqlsrv_fetch_array($res);
  550.             $stats['actual_devices'$row['devcount'];
  551.             sqlsrv_free_stmt($res);
  552.         }
  553.         return $stats;
  554.     }
  555.     public function getCachedUserAgents(){
  556.         $uas array();
  557.         $cacheres sqlsrv_query($this->dbcon,"SELECT user_agent FROM ".TeraWurflConfig::$TABLE_PREFIX.'Cache'." ORDER BY user_agent");
  558.         while($ua sqlsrv_fetch_array($cacheres,SQLSRV_FETCH_NUMERIC))$uas[]=$ua[0];
  559.         sqlsrv_free_stmt($cacheres);
  560.         return $uas;
  561.     }
  562.     protected function lastDBError(){
  563.         $errors sqlsrv_errors();
  564.         return isset($errors[0])$errors[0]['message']"none";
  565.     }
  566.     public function getServerVersion(){
  567.         $res sqlsrv_query($this->dbcon,"SELECT @@version Stable 2.1.3 $Date: 2010/09/18 15:43:21
  568.         $row = sqlsrv_fetch_array($res);
  569.         sqlsrv_free_stmt($res);
  570.         preg_match('/^([^)]+\))/',$row['server_version'],$matches);
  571.         return $matches[1];
  572.     }

Documentation generated on Sun, 19 Sep 2010 00:15:59 +0000 by phpDocumentor 1.4.3