PageRenderTime 46ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/plugins/system/jfdatabase/intercept.jdatabasemysql.php

https://github.com/Shigaru/shigaru
PHP | 342 lines | 206 code | 65 blank | 71 comment | 67 complexity | d985464dab3bd0108a2e77612babe925 MD5 | raw file
  1. <?php
  2. /**
  3. * Joom!Fish - Multi Lingual extention and translation manager for Joomla!
  4. * Copyright (C) 2003 - 2012, Think Network GmbH, Munich
  5. *
  6. * All rights reserved. The Joom!Fish project is a set of extentions for
  7. * the content management system Joomla!. It enables Joomla!
  8. * to manage multi lingual sites especially in all dynamic information
  9. * which are stored in the database.
  10. *
  11. * This program is free software; you can redistribute it and/or
  12. * modify it under the terms of the GNU General Public License
  13. * as published by the Free Software Foundation; either version 2
  14. * of the License, or (at your option) any later version.
  15. *
  16. * This program is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. * GNU General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU General Public License
  22. * along with this program; if not, write to the Free Software
  23. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,USA.
  24. *
  25. * The "GNU General Public License" (GPL) is available at
  26. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  27. * -----------------------------------------------------------------------------
  28. * $Id: intercept.jdatabasemysql.php 1592 2012-01-20 12:51:08Z akede $
  29. * @package joomfish
  30. * @subpackage jfdatabase
  31. * @version 2.0
  32. *
  33. */
  34. // Don't allow direct linking
  35. defined( '_JEXEC' ) or die( 'Direct Access to this location is not allowed.' );
  36. class interceptDB extends JDatabaseMySQL {
  37. /**
  38. * This special constructor reuses the existing resource from the existing db connecton
  39. *
  40. * @param unknown_type $options
  41. */
  42. function __construct($options){
  43. $db = JFactory::getDBO();
  44. // support for recovery of existing connections (Martin N. Brampton)
  45. if (isset($this->_options)) $this->_options = $options;
  46. $select = array_key_exists('select', $options) ? $options['select'] : true;
  47. $database = array_key_exists('database',$options) ? $options['database'] : '';
  48. // perform a number of fatality checks, then return gracefully
  49. if (!function_exists( 'mysql_connect' )) {
  50. $this->_errorNum = 1;
  51. $this->_errorMsg = 'The MySQL adapter "mysql" is not available.';
  52. return;
  53. }
  54. // connect to the server
  55. $this->_resource = $db->_resource;
  56. // finalize initialization
  57. JDatabase::__construct($options);
  58. // select the database
  59. if ( $select ) {
  60. $this->select($database);
  61. }
  62. }
  63. function _getFieldCount(){
  64. if (!is_resource($this->_cursor)){
  65. // This is a serious problem since we do not have a valid db connection
  66. // or there is an error in the query
  67. $error = JError::raiseError( 500, JTEXT::_('No valid database connection:') .$this->getErrorMsg());
  68. return $error;
  69. }
  70. $fields = mysql_num_fields($this->_cursor);
  71. return $fields;
  72. }
  73. function _getFieldMetaData($i){
  74. $meta = mysql_fetch_field($this->_cursor, $i);
  75. return $meta;
  76. }
  77. function fillRefTableCache($cacheDir,$cacheFile){
  78. $pfunc = $this->_profile();
  79. $cacheFileContent = serialize($this->_refTables);
  80. JFile::write($cacheFile,$cacheFileContent);
  81. // clean out old cache files
  82. // This could be very slow for long list of old files -
  83. // TODO store in database instead
  84. $this->cleanRefTableCache($cacheDir);
  85. $pfunc = $this->_profile($pfunc);
  86. }
  87. function cleanRefTableCache($cacheDir){
  88. $pfunc = $this->_profile();
  89. $files =JFolder::files($cacheDir);
  90. foreach ($files as $file) {
  91. if (($file != '.') && ($file != '..')) {
  92. $file = "$cacheDir/$file";
  93. if (JFile::exists($file) && @filemtime($file) < $this->cacheExpiry) {
  94. if (!JFile::delete($file)) {
  95. JError::raiseWarning ( 200, JText::_('problems clearing cache file ' .$file));
  96. }
  97. }
  98. }
  99. }
  100. $pfunc = $this->_profile($pfunc);
  101. return true;
  102. }
  103. function _logSetRefTablecache($action,$tempsql,$sql_exNos,$sqlHash){
  104. $pfunc = $this->_profile();
  105. $logfile = dirname(__FILE__)."/qalog.txt";
  106. $handle = fopen($logfile,"ab");
  107. // replace tabs and carriage returns with spaces
  108. fwrite($handle,"$action ");
  109. fwrite($handle,preg_replace("/([\t\n\r\f])/"," ",$tempsql));
  110. fwrite($handle," #@�^�@# ");
  111. fwrite($handle,preg_replace("/([\t\n\r\f])/"," ",$sql_exNos));
  112. fwrite($handle," #@�^�@# ");
  113. fwrite($handle,preg_replace("/([\t\n\r\f])/"," ",$sqlHash));
  114. fwrite($handle," # JF LINE END# \n");
  115. fclose($handle);
  116. $pfunc = $this->_profile($pfunc);
  117. }
  118. function setRefTables(){
  119. $pfunc = $this->_profile();
  120. // Before joomfish manager is created since we can't translate so skip this anaylsis
  121. $jfManager = JoomFishManager::getInstance();
  122. if (!$jfManager) return;
  123. // This could be speeded up by the use of a cache - but only of benefit is global caching is off
  124. $tempsql = $this->_sql;
  125. // only needed for selects at present - possibly add for inserts/updates later
  126. if (strpos(strtoupper(trim($tempsql)),"SELECT")!==0) {
  127. $pfunc = $this->_profile($pfunc);
  128. return;
  129. }
  130. // Ignore Joomfish translation query
  131. if (strpos($tempsql,"SELECT jf_content.reference_field, jf_content.value")===0){
  132. $pfunc = $this->_profile($pfunc);
  133. return;
  134. }
  135. $config = JFactory::getConfig();
  136. jimport('joomla.client.helper');
  137. $FTPOptions = JClientHelper::getCredentials('ftp');
  138. // we won't use this caching if FTP layer ie enabled
  139. if ($jfManager->getCfg("qacaching",1) && $FTPOptions['enabled'] == 1){
  140. $cachepath = JPATH_CACHE;
  141. $cachetime = $config->getValue('config.cachetime',0);
  142. // remove time formats (assume all numbers are not necessay - this is experimental
  143. // for example table names or column names could contain numbers
  144. // so this version only replaces numbers not adjacent to alpha characters i.e.field2 doesn't become field
  145. $sql_exNos = preg_replace("/(?![a-z])(.)([0-9]+)(?![a-z]+)/i",'${1}',$tempsql);
  146. $sql_exNos = preg_replace("/(?![a-z]).([0-9]+)$/i",'${1}',$sql_exNos);
  147. if ( $config->getValue('config.debug',0)) {
  148. echo "<p style='background-color:bisque;border:solid 1px black'><strong>setRefTables debug:</strong><br / >"
  149. . "tempsql = $tempsql<br />"
  150. . "sql_exNos = $sql_exNos"
  151. . "</p>";
  152. }
  153. $sqlHash = md5($sql_exNos );
  154. $this->cacheExpiry = time() - $cachetime;
  155. $cacheDir = "$cachepath/refTableSQL";
  156. if (!JFolder::exists($cacheDir)) JFolder::create($cacheDir);
  157. $cacheFile = "$cacheDir/$sqlHash";
  158. if (JFile::exists($cacheFile) && @filemtime($cacheFile) > $this->cacheExpiry) {
  159. $cacheFileContent = JFile::read($cacheFile);
  160. $this->_refTables = unserialize($cacheFileContent);
  161. if ($jfManager->getCfg("qalogging",0)){
  162. $this->_logSetRefTablecache("r",$tempsql,$sql_exNos,$sqlHash);
  163. }
  164. $pfunc = $this->_profile($pfunc);
  165. return;
  166. }
  167. if($this->_cursor===true || $this->_cursor===false) {
  168. if ($jfManager->getCfg("qalogging",0)){
  169. $this->_logSetRefTablecache("wtf",$tempsql,$sql_exNos,$sqlHash);
  170. }
  171. $this->fillRefTableCache($cacheDir,$cacheFile);
  172. $pfunc = $this->_profile($pfunc);
  173. return;
  174. }
  175. }
  176. // get column metadata
  177. $fields = $this->_getFieldCount();
  178. //print "<br> $tempsql $this->_cursor $fields";
  179. if ($jfManager->getCfg("qacaching",1) && $FTPOptions['enabled'] == 1){
  180. if ($fields<=0) {
  181. if ($jfManager->getCfg("qalogging",0)){
  182. $this->_logSetRefTablecache("w0f",$tempsql,$sql_exNos,$sqlHash);
  183. }
  184. $this->fillRefTableCache($cacheDir,$cacheFile);
  185. $pfunc = $this->_profile($pfunc);
  186. return;
  187. }
  188. }
  189. if ($fields<=0) {
  190. $pfunc = $this->_profile($pfunc);
  191. return;
  192. }
  193. $this->_refTables=array();
  194. $this->_refTables["fieldTablePairs"]=array();
  195. $this->_refTables["tableAliases"]=array();
  196. $this->_refTables["reverseTableAliases"]=array();
  197. $this->_refTables["fieldAliases"]=array();
  198. $this->_refTables["fieldTableAliasData"]=array();
  199. $this->_refTables["fieldCount"]=$fields;
  200. $this->_refTables["sql"]=$tempsql;
  201. // local variable to keep track of aliases that have already been analysed
  202. $tableAliases = array();
  203. for ($i = 0; $i < $fields; ++$i) {
  204. $meta = $this->_getFieldMetaData($i);
  205. if (!$meta) {
  206. echo JText::_("No information available<br />\n");
  207. }
  208. else {
  209. $tempTable = $meta->table;
  210. // if I have already found the table alias no need to do it again!
  211. if (array_key_exists($tempTable,$tableAliases)){
  212. $value = $tableAliases[$tempTable];
  213. }
  214. // mysli only
  215. else if (isset($meta->orgtable)){
  216. $value = $meta->orgtable;
  217. if (isset($this->_table_prefix) && strlen($this->_table_prefix)>0 && strpos($meta->orgtable,$this->_table_prefix)===0) $value = substr($meta->orgtable, strlen( $this->_table_prefix));
  218. $tableAliases[$tempTable] = $value;
  219. }
  220. else {
  221. if (!isset($tempTable) || strlen($tempTable)==0) {
  222. continue;
  223. }
  224. //echo "<br>Information for column $i of ".($fields-1)." ".$meta->name." : $tempTable=";
  225. $tempArray=array();
  226. $prefix = $this->_table_prefix;
  227. preg_match_all("/`?$prefix(\w+)`?\s+(?:AS\s)?+`?".$tempTable."`?[,\s]/i",$this->_sql, $tempArray, PREG_PATTERN_ORDER);
  228. //preg_match_all("/`?$prefix(\w+)`?\s+AS\s+`?".$tempTable."`?[,\s]/i",$this->_sql, $tempArray, PREG_PATTERN_ORDER);
  229. if (count($tempArray)>1 && count($tempArray[1])>0) $value = $tempArray[1][0];
  230. else $value = null;
  231. if (isset($this->_table_prefix) && strlen($this->_table_prefix)>0 && strpos($tempTable,$this->_table_prefix)===0) $tempTable = substr($tempTable, strlen( $this->_table_prefix));
  232. $value = $value?$value:$tempTable;
  233. $tableAliases[$tempTable]=$value;
  234. }
  235. if ((!($value=="session" || strpos($value,"jf_")===0)) && $this->translatedContentAvailable($value)){
  236. /// ARGH !!! I must also look for aliases for fieldname !!
  237. if (isset($meta->orgname)){
  238. $nameValue = $meta->orgname;
  239. }
  240. else {
  241. $tempName = $meta->name;
  242. $tempArray=array();
  243. // This is a bad match when we have "SELECT id" at the start of the query
  244. preg_match_all("/`?(\w+)`?\s+(?:AS\s)?+`?".$tempName."`?[,\s]/i",$this->_sql, $tempArray, PREG_PATTERN_ORDER);
  245. //preg_match_all("/`?(\w+)`?\1s+AS\s+`?".$tempName."`?[,\s]/i",$this->_sql, $tempArray, PREG_PATTERN_ORDER);
  246. if (count($tempArray)>1 && count($tempArray[1])>0) {
  247. //echo "$meta->name is an alias for ".$tempArray[1][0]."<br>";
  248. // must ignore "SELECT id"
  249. if (strtolower($tempArray[1][0])=="select"){
  250. $nameValue = $meta->name;
  251. }
  252. else {
  253. $nameValue = $tempArray[1][0];
  254. }
  255. }
  256. else $nameValue = $meta->name;
  257. }
  258. if (!array_key_exists($value,$this->_refTables["tableAliases"])) $this->_refTables["tableAliases"][$value]=$meta->table;
  259. if (!array_key_exists($meta->table,$this->_refTables["reverseTableAliases"])) $this->_refTables["reverseTableAliases"][$meta->table]=$value;
  260. // I can't use the field name as the key since it may not be unique!
  261. if (!in_array($value,$this->_refTables["fieldTablePairs"])) $this->_refTables["fieldTablePairs"][]=$value;
  262. if (!array_key_exists($nameValue,$this->_refTables["fieldAliases"])) $this->_refTables["fieldAliases"][$meta->name]=$nameValue;
  263. // Put all the mapping data together so that everything is in sync and I can check fields vs aliases vs tables in one place
  264. $this->_refTables["fieldTableAliasData"][$i]=array("fieldNameAlias"=>$meta->name, "fieldName"=>$nameValue,"tableNameAlias"=>$meta->table,"tableName"=>$value);
  265. }
  266. }
  267. }
  268. if ($jfManager->getCfg("qacaching",1) && $fields>1 && $FTPOptions['enabled'] == 1){
  269. if ($jfManager->getCfg("qalogging",0)){
  270. $this->_logSetRefTablecache("wn",$tempsql,$sql_exNos,$sqlHash);
  271. }
  272. $this->fillRefTableCache($cacheDir,$cacheFile);
  273. }
  274. $pfunc = $this->_profile($pfunc);
  275. }
  276. }
  277. ?>