00001 <?php
00002
00006 class oxSysRequirements
00007 {
00013 protected $_aRequiredModules = null;
00014
00020 protected $_blSysReqStatus = null;
00021
00027 protected $_aException = array( 'OXDELIVERY' => 'OXDELTYPE',
00028 'OXSELECTLIST' => 'OXIDENT');
00029
00035 protected $_aColumns = array( 'OXID',
00036 'OXOBJECTID',
00037 'OXARTICLENID',
00038 'OXACTIONID',
00039 'OXARTID',
00040 'OXUSERID',
00041 'OXADDRESSUSERID',
00042 'OXCOUNTRYID',
00043 'OXSESSID',
00044 'OXITMID',
00045 'OXPARENTID',
00046 'OXAMITEMID',
00047 'OXAMTASKID',
00048 'OXVENDORID',
00049 'OXMANUFACTURERID',
00050 'OXROOTID',
00051 'OXATTRID',
00052 'OXCATID',
00053 'OXDELID',
00054 'OXDELSETID',
00055 'OXITMARTID',
00056 'OXFIELDID',
00057 'OXROLEID',
00058 'OXCNID',
00059 'OXANID',
00060 'OXARTICLENID',
00061 'OXCATNID',
00062 'OXDELIVERYID',
00063 'OXDISCOUNTID',
00064 'OXGROUPSID',
00065 'OXLISTID',
00066 'OXPAYMENTID',
00067 'OXDELTYPE',
00068 'OXROLEID',
00069 'OXSELNID',
00070 'OXBILLCOUNTRYID',
00071 'OXDELCOUNTRYID',
00072 'OXPAYMENTID',
00073 'OXCARDID',
00074 'OXPAYID',
00075 'OXIDENT',
00076 'OXDEFCAT',
00077 'OXBASKETID',
00078 'OXPAYMENTSID',
00079 'OXORDERID',
00080 'OXVOUCHERSERIEID');
00081
00087 protected $_sReqInfoUrl = "http://www.oxidforge.org/wiki/Installation";
00088
00094 protected $_aInfoMap = array( "php_version" => "PHP_version_at_least_5.2.0",
00095 "lib_xml2" => "LIB_XML2",
00096 "php_xml" => "DOM",
00097 "open_ssl" => "OpenSSL",
00098 "soap" => "SOAP",
00099 "j_son" => "JSON",
00100 "i_conv" => "ICONV",
00101 "tokenizer" => "Tokenizer",
00102 "mysql_connect" => "MySQL_client_connector_for_MySQL_5",
00103 "gd_info" => "GDlib_v2_.5Bv1.5D_incl._JPEG_support",
00104 "mb_string" => "mbstring",
00105 "bc_math" => "BCMath",
00106 "allow_url_fopen" => "allow_url_fopen_or_fsockopen_to_port_80",
00107 "php4_compat" => "Zend_compatibility_mode_must_be_off",
00108 "request_uri" => "REQUEST_URI_set",
00109 "ini_set" => "ini_set_allowed",
00110 "register_globals" => "register_globals_must_be_off",
00111 "memory_limit" => "PHP_Memory_limit_.28min._14MB.2C_30MB_recommended.29",
00112 "unicode_support" => "UTF-8_support",
00113 "mod_rewrite" => "apache_mod_rewrite_module",
00114 "server_permissions" => "Files_.26_Folder_Permission_Setup",
00115 "zend_optimizer" => "Zend_Optimizer",
00116 "bug53632" => "Not_recommended_PHP_versions",
00117
00118 );
00119
00125 public function __construct()
00126 {
00127 }
00128
00140 public function __call( $sMethod, $aArgs )
00141 {
00142 if ( defined( 'OXID_PHP_UNIT' ) ) {
00143 if ( substr( $sMethod, 0, 4) == "UNIT" ) {
00144 $sMethod = str_replace( "UNIT", "_", $sMethod );
00145 }
00146 if ( method_exists( $this, $sMethod)) {
00147 return call_user_func_array( array( & $this, $sMethod ), $aArgs );
00148 }
00149 }
00150
00151 throw new oxSystemComponentException( "Function '$sMethod' does not exist or is not accessible! (" . get_class($this) . ")".PHP_EOL);
00152 }
00153
00159 public function getConfig()
00160 {
00161 return oxConfig::getInstance();
00162 }
00163
00169 public function getRequiredModules()
00170 {
00171 if ( $this->_aRequiredModules == null ) {
00172 $aRequiredPHPExtensions = array(
00173 'php_version',
00174 'lib_xml2',
00175 'php_xml',
00176 'j_son',
00177 'i_conv',
00178 'tokenizer',
00179 'mysql_connect',
00180 'gd_info',
00181 'mb_string',
00182 'curl',
00183 'bc_math',
00184 'open_ssl',
00185 'soap',
00186 );
00187
00188 $aRequiredPHPConfigs = array(
00189 'allow_url_fopen',
00190 'php4_compat',
00191 'request_uri',
00192 'ini_set',
00193 'register_globals',
00194 'memory_limit',
00195 'unicode_support'
00196 );
00197
00198 $aRequiredServerConfigs = array(
00199 'mod_rewrite',
00200 'server_permissions',
00201 'bug53632'
00202 );
00203
00204
00205 if ( isAdmin() ) {
00206 $aRequiredServerConfigs[] = 'mysql_version';
00207 }
00208 $this->_aRequiredModules = array_fill_keys( $aRequiredPHPExtensions, 'php_extennsions' ) +
00209 array_fill_keys( $aRequiredPHPConfigs, 'php_config' ) +
00210 array_fill_keys( $aRequiredServerConfigs, 'server_config' );
00211 }
00212 return $this->_aRequiredModules;
00213 }
00214
00223 public function checkBug53632()
00224 {
00225 $iState = 1;
00226 if ( version_compare( PHP_VERSION, "5.3", ">=" ) ) {
00227 if ( version_compare( PHP_VERSION, "5.3.5", ">=" ) && version_compare( PHP_VERSION, "5.3.7", "!=" ) ) {
00228 $iState = 2;
00229 }
00230 } elseif ( version_compare( PHP_VERSION, '5.2', ">=" ) ) {
00231 $iState = version_compare( PHP_VERSION, "5.2.17", ">=" ) ? 2 : $iState;
00232 }
00233 return $iState;
00234 }
00235
00241 public function checkCurl()
00242 {
00243 return extension_loaded( 'curl' ) ? 2 : 1;
00244 }
00245
00251 public function checkMbString()
00252 {
00253 return extension_loaded( 'mbstring' ) ? 2 : 1;
00254 }
00255
00264 public function checkServerPermissions( $sPath = null, $iMinPerm = 777 )
00265 {
00266 $sVerPrefix = '';
00267
00268 clearstatcache();
00269 $sPath = $sPath ? $sPath : getShopBasePath();
00270
00271
00272 $sFullPath = $sPath . "config.inc.php";
00273 if ( !is_readable( $sFullPath ) ||
00274 ( isAdmin() && is_writable( $sFullPath ) ) ||
00275 ( !isAdmin() && !is_writable( $sFullPath ) )
00276 ) {
00277 return 0;
00278 }
00279
00280 $sTmp = "$sPath/tmp$sVerPrefix/";
00281 if (class_exists('oxConfig')) {
00282 $sCfgTmp = $this->getConfig()->getConfigParam('sCompileDir');
00283 if (strpos($sCfgTmp, '<sCompileDir_') === false) {
00284 $sTmp = $sCfgTmp;
00285 }
00286 }
00287
00288 $aPathsToCheck = array(
00289 $sPath."out/pictures{$sVerPrefix}/promo/",
00290 $sPath."out/pictures{$sVerPrefix}/media/",
00291 $sPath."out/pictures{$sVerPrefix}/master/",
00292 $sPath."out/pictures{$sVerPrefix}/generated/",
00293 $sPath."log/",
00294 $sTmp
00295 );
00296 $iModStat = 2;
00297 $sPathToCheck = reset( $aPathsToCheck );
00298 while ( $sPathToCheck ) {
00299
00300 if ( !file_exists( $sPathToCheck ) ) {
00301 $iModStat = 0;
00302 break;
00303 }
00304
00305 if ( is_dir( $sPathToCheck ) ) {
00306
00307 $aSubF = glob( $sPathToCheck."*", GLOB_ONLYDIR );
00308 if (is_array($aSubF)) {
00309 foreach ( $aSubF as $sNewFolder ) {
00310 $aPathsToCheck[] = $sNewFolder . "/";
00311 }
00312 }
00313 }
00314
00315
00316
00317 if ( !is_readable( $sPathToCheck ) || !is_writable( $sPathToCheck ) ) {
00318 $iModStat = 0;
00319 break;
00320 }
00321
00322 $sPathToCheck = next( $aPathsToCheck );
00323 }
00324
00325 return $iModStat;
00326 }
00327
00334 protected function _getShopHostInfoFromConfig()
00335 {
00336 $sShopURL = $this->getConfig()->getConfigParam( 'sShopURL' );
00337 if (preg_match('#^(https?://)?([^/:]+)(:([0-9]+))?(/.*)?$#i', $sShopURL, $m)) {
00338 $sHost = $m[2];
00339 $iPort = (int)$m[4];
00340 $blSsl = (strtolower($m[1])=='https://');
00341 if (!$iPort) {
00342 $iPort = $blSsl?443:80;
00343 }
00344 $sScript = rtrim($m[5], '/').'/';
00345 return array(
00346 'host'=>$sHost,
00347 'port'=>$iPort,
00348 'dir'=>$sScript,
00349 'ssl'=>$blSsl,
00350 );
00351 } else {
00352 return false;
00353 }
00354 }
00355
00362 protected function _getShopHostInfoFromServerVars()
00363 {
00364
00365 $sScript = $_SERVER['SCRIPT_NAME'];
00366 $iPort = (int) $_SERVER['SERVER_PORT'];
00367 $blSsl = (isset($_SERVER['HTTPS']) && ($_SERVER['HTTPS'] == 'on'));
00368 if (!$iPort) {
00369 $iPort = $blSsl?443:80;
00370 }
00371 $sScript = rtrim(dirname(dirname( $sScript )), '/').'/';
00372 return array(
00373 'host'=>$_SERVER['HTTP_HOST'],
00374 'port'=>$iPort,
00375 'dir'=>$sScript,
00376 'ssl'=>$blSsl,
00377 );
00378 }
00379
00385 protected function _getShopHostInfo()
00386 {
00387 if ( isAdmin() ) {
00388 return $this->_getShopHostInfoFromConfig();
00389 } else {
00390 return $this->_getShopHostInfoFromServerVars();
00391 }
00392 }
00393
00399 public function checkModRewrite()
00400 {
00401 $iModStat = null;
00402 if ( ($aHostInfo = $this->_getShopHostInfo()) && $rFp = @fsockopen( ($aHostInfo['ssl']?'ssl://':'').$aHostInfo['host'], $aHostInfo['port'], $iErrNo, $sErrStr, 10 ) ) {
00403 $sReq = "POST {$aHostInfo['dir']}oxseo.php?mod_rewrite_module_is=off HTTP/1.1\r\n";
00404 $sReq .= "Host: {$aHostInfo['host']}\r\n";
00405 $sReq .= "User-Agent: OXID eShop setup\r\n";
00406 $sReq .= "Content-Type: application/x-www-form-urlencoded\r\n";
00407 $sReq .= "Content-Length: 0\r\n";
00408 $sReq .= "Connection: close\r\n\r\n";
00409
00410 $sOut = '';
00411 fwrite( $rFp, $sReq );
00412 while ( !feof( $rFp ) ) {
00413 $sOut .= fgets( $rFp, 100 );
00414 }
00415 fclose( $rFp );
00416
00417 $iModStat = ( strpos( $sOut, 'mod_rewrite_on' ) !== false ) ? 2 : 0;
00418 } else {
00419 if ( function_exists( 'apache_get_modules' ) ) {
00420
00421 $iModStat = in_array( 'mod_rewrite', apache_get_modules() ) ? 1 : 0;
00422 } else {
00423 $iModStat = -1;
00424 }
00425 }
00426 return $iModStat;
00427 }
00428
00434 public function checkAllowUrlFopen()
00435 {
00436 $iModStat = @ini_get('allow_url_fopen');
00437 $iModStat = ( $iModStat && strcasecmp( '1', $iModStat ) ) ? 2 : 1;
00438 if ( $iModStat == 1 ) {
00439 $iErrNo = 0;
00440 $sErrStr = '';
00441 if ( $oRes = @fsockopen( 'www.example.com', 80, $iErrNo, $sErrStr, 10 ) ) {
00442 $iModStat = 2;
00443 fclose( $oRes );
00444 }
00445 }
00446 $iModStat = ( !$iModStat ) ? 1 : $iModStat;
00447 return $iModStat;
00448 }
00449
00456 public function checkPhp4Compat()
00457 {
00458 $sZendStatus = ( strtolower( (string) @ini_get( 'zend.ze1_compatibility_mode' ) ) );
00459 return in_array( $sZendStatus, array( 'on', '1' ) ) ? 0 : 2;
00460 }
00461
00468 public function checkPhpVersion()
00469 {
00470 $iModStat = ( version_compare( PHP_VERSION, '5.1', '>' ) ) ? 1 : 0;
00471 $iModStat = ( $iModStat == 0 ) ? $iModStat : ( version_compare( PHP_VERSION, '5.2', '>=' ) ? 2 : 1 );
00472 return $iModStat;
00473 }
00474
00480 public function checkRequestUri()
00481 {
00482 return ( isset( $_SERVER['REQUEST_URI'] ) || isset( $_SERVER['SCRIPT_URI'] ) ) ? 2 : 0;
00483 }
00484
00490 public function checkLibXml2()
00491 {
00492 return class_exists( 'DOMDocument' ) ? 2 : 0;
00493 }
00494
00500 public function checkPhpXml()
00501 {
00502 return class_exists( 'DOMDocument' ) ? 2 : 0;
00503 }
00504
00510 public function checkJSon()
00511 {
00512 return extension_loaded( 'json' ) ? 2 : 0;
00513 }
00514
00520 public function checkIConv()
00521 {
00522 return extension_loaded( 'iconv' ) ? 2 : 0;
00523 }
00524
00530 public function checkTokenizer()
00531 {
00532 return extension_loaded( 'tokenizer' ) ? 2 : 0;
00533 }
00534
00540 public function checkBcMath()
00541 {
00542 return extension_loaded( 'bcmath' ) ? 2 : 1;
00543 }
00544
00550 public function checkOpenSsl()
00551 {
00552 return extension_loaded( 'openssl' ) ? 2 : 1;
00553 }
00554
00560 public function checkSoap()
00561 {
00562 return extension_loaded( 'soap' ) ? 2 : 1;
00563 }
00564
00570 public function checkMysqlConnect()
00571 {
00572
00573 $iModStat = ( extension_loaded( 'mysql' ) || extension_loaded( 'mysqli' ) || extension_loaded( 'pdo_mysql' ) || extension_loaded( 'mysqlnd' ) ) ? 2 : 0;
00574
00575 if ( $iModStat ) {
00576 $sClientVersion = mysql_get_client_info();
00577 if (version_compare( $sClientVersion, '5', '<' )) {
00578 $iModStat = 1;
00579 if (version_compare( $sClientVersion, '4', '<' )) {
00580 $iModStat = 0;
00581 }
00582 } elseif (version_compare($sClientVersion, '5.0.36', '>=') && version_compare($sClientVersion, '5.0.38', '<')) {
00583
00584 $iModStat = 0;
00585 } elseif (version_compare($sClientVersion, '5.0.40', '>') && version_compare($sClientVersion, '5.0.42', '<')) {
00586
00587 $iModStat = 0;
00588 }
00589 }
00590 return $iModStat;
00591 }
00592
00600 public function checkMysqlVersion( $sVersion = null )
00601 {
00602 if ( $sVersion === null ) {
00603 $aRez = oxDb::getDb()->getAll( "SHOW VARIABLES LIKE 'version'" );
00604 foreach ( $aRez as $aRecord ) {
00605 $sVersion = $aRecord[1];
00606 break;
00607 }
00608 }
00609
00610 $iModStat = 0;
00611 if ( version_compare( $sVersion, '5.0.3', '>=' ) && version_compare( $sVersion, '5.0.37', '<>' ) ) {
00612 $iModStat = 2;
00613 }
00614
00615 return $iModStat;
00616 }
00617
00623 public function checkGdInfo()
00624 {
00625 $iModStat = extension_loaded( 'gd' ) ? 1 : 0;
00626 $iModStat = function_exists( 'imagecreatetruecolor' ) ? 2 : $iModStat;
00627 $iModStat = function_exists( 'imagecreatefromjpeg' ) ? $iModStat : 0;
00628 return $iModStat;
00629 }
00630
00636 public function checkIniSet()
00637 {
00638 return ( @ini_set('session.name', 'sid' ) !== false ) ? 2 : 0;
00639 }
00640
00646 public function checkRegisterGlobals()
00647 {
00648 $sGlobStatus = ( strtolower( (string) @ini_get( 'register_globals' ) ) );
00649 return in_array( $sGlobStatus, array( 'on', '1' ) ) ? 0 : 2;
00650 }
00651
00657 public function checkMemoryLimit()
00658 {
00659 if ( $sMemLimit = @ini_get('memory_limit') ) {
00660
00661 $sDefLimit = '14M';
00662 $sRecLimit = '30M';
00663
00664
00665 $iMemLimit = $this->_getBytes( $sMemLimit );
00666 $iModStat = ( $iMemLimit >= $this->_getBytes( $sDefLimit ) ) ? 1 : 0;
00667 $iModStat = $iModStat ? ( ( $iMemLimit >= $this->_getBytes( $sRecLimit ) ) ? 2 : $iModStat ) : $iModStat;
00668
00669 } else {
00670 $iModStat = -1;
00671 }
00672 return $iModStat;
00673 }
00674
00680 public function checkZendOptimizer()
00681 {
00686 return 2;
00687 }
00688
00694 public function checkZendPlatformOrServer()
00695 {
00696 if (function_exists( 'output_cache_get' )) {
00697 return 2;
00698 }
00699 if (function_exists( 'zend_disk_cache_fetch' )) {
00700 return 2;
00701 }
00702 if (function_exists( 'zend_shm_cache_fetch' )) {
00703 return 2;
00704 }
00705 return 1;
00706 }
00707
00713 protected function _getAdditionalCheck()
00714 {
00715 $sSelect = '';
00716 foreach ( $this->_aException as $sTable => $sColumn ) {
00717 $sSelect .= 'and ( t.TABLE_NAME != "'.$sTable.'" and c.COLUMN_NAME != "'.$sColumn.'" ) ';
00718 }
00719 return $sSelect;
00720 }
00721
00727 public function checkCollation()
00728 {
00729 $myConfig = $this->getConfig();
00730
00731 $aCollations = array();
00732 $sCollation = '';
00733
00734 $sSelect = 'select t.TABLE_NAME, c.COLUMN_NAME, c.COLLATION_NAME from INFORMATION_SCHEMA.tables t ' .
00735 'LEFT JOIN INFORMATION_SCHEMA.columns c ON t.TABLE_NAME = c.TABLE_NAME ' .
00736 'where t.TABLE_SCHEMA = "'.$myConfig->getConfigParam( 'dbName' ).'" ' .
00737 'and c.TABLE_SCHEMA = "'.$myConfig->getConfigParam( 'dbName' ).'" ' .
00738 'and c.COLUMN_NAME in ("'.implode('", "', $this->_aColumns).'") ' . $this->_getAdditionalCheck() .
00739 ' ORDER BY (t.TABLE_NAME = "oxarticles") DESC';
00740 $aRez = oxDb::getDb()->getAll($sSelect);
00741 foreach ( $aRez as $aRetTable ) {
00742 if ( !$sCollation ) {
00743 $sCollation = $aRetTable[2];
00744 } else {
00745 if ( $aRetTable[2] && $sCollation != $aRetTable[2]) {
00746 $aCollations[$aRetTable[0]][$aRetTable[1]] = $aRetTable[2];
00747 }
00748 }
00749 }
00750
00751 if ( $this->_blSysReqStatus === null ) {
00752 $this->_blSysReqStatus = true;
00753 }
00754 if ( count($aCollations) > 0 ) {
00755 $this->_blSysReqStatus = false;
00756 }
00757 return $aCollations;
00758 }
00759
00765 public function checkDatabaseCluster()
00766 {
00767 return 2;
00768 }
00769
00775 public function checkUnicodeSupport()
00776 {
00777 return (@preg_match('/\pL/u', 'a') == 1) ? 2 : 1;
00778 }
00779
00785 public function getSysReqStatus()
00786 {
00787 if ( $this->_blSysReqStatus == null ) {
00788 $this->_blSysReqStatus = true;
00789 $this->getSystemInfo();
00790 $this->checkCollation();
00791 }
00792 return $this->_blSysReqStatus;
00793 }
00794
00809 public function getSystemInfo()
00810 {
00811 $aSysInfo = array();
00812 $aRequiredModules = $this->getRequiredModules();
00813 $this->_blSysReqStatus = true;
00814 foreach ( $aRequiredModules as $sModule => $sGroup ) {
00815 if ( isset($aSysInfo[$sGroup]) && !$aSysInfo[$sGroup] ) {
00816 $aSysInfo[$sGroup] = array();
00817 }
00818 $iModuleState = $this->getModuleInfo( $sModule );
00819 $aSysInfo[$sGroup][$sModule] = $iModuleState;
00820 $this->_blSysReqStatus = $this->_blSysReqStatus && ( bool ) abs( $iModuleState );
00821 }
00822 return $aSysInfo;
00823 }
00824
00832 public function getModuleInfo( $sModule = null )
00833 {
00834 if ( $sModule ) {
00835 $iModStat = null;
00836 $sCheckFunction = "check".str_replace(" ", "", ucwords(str_replace("_", " ", $sModule)));
00837 $iModStat = $this->$sCheckFunction();
00838
00839 return $iModStat;
00840 }
00841 }
00842
00850 public function getReqInfoUrl( $sIdent)
00851 {
00852 $sUrl = $this->_sReqInfoUrl;
00853 $aInfoMap = $this->_aInfoMap;
00854
00855
00856 if ( isset( $aInfoMap[$sIdent] ) ) {
00857 $sUrl .= "#".$aInfoMap[$sIdent];
00858 }
00859
00860 return $sUrl;
00861 }
00862
00870 protected function _getBytes( $sBytes )
00871 {
00872 $sBytes = trim( $sBytes );
00873 $sLast = strtolower($sBytes[strlen($sBytes)-1]);
00874 switch( $sLast ) {
00875
00876 case 'g':
00877 $sBytes *= 1024;
00878 case 'm':
00879 $sBytes *= 1024;
00880 case 'k':
00881 $sBytes *= 1024;
00882 break;
00883 }
00884
00885 return $sBytes;
00886 }
00887
00898 protected function _checkTemplateBlock($sTemplate, $sBlockName)
00899 {
00900 $sTplFile = $this->getConfig()->getTemplatePath($sTemplate, false);
00901 if (!$sTplFile || !file_exists($sTplFile)) {
00902 return false;
00903 }
00904
00905 $sFile = file_get_contents($sTplFile);
00906 $sBlockNameQuoted = preg_quote($sBlockName, '/');
00907 return (bool)preg_match('/\[\{\s*block\s+name\s*=\s*([\'"])'.$sBlockNameQuoted.'\1\s*\}\]/is', $sFile);
00908 }
00909
00919 public function getMissingTemplateBlocks()
00920 {
00921 $oDb = oxDb::getDb( true );
00922 $aCache = array();
00923 $oConfig = $this->getConfig();
00924
00925 $sShpIdParam = $oDb->quote($oConfig->getShopId());
00926 $sSql = "select * from oxtplblocks where oxactive=1 and oxshopid=$sShpIdParam";
00927 $rs = $oDb->execute($sSql);
00928 $aRet = array();
00929 if ($rs != false && $rs->recordCount() > 0) {
00930 while (!$rs->EOF) {
00931 $blStatus = false;
00932 if (isset($aCache[$rs->fields['OXTEMPLATE']]) && isset($aCache[$rs->fields['OXTEMPLATE']][$rs->fields['OXBLOCKNAME']])) {
00933 $blStatus = $aCache[$rs->fields['OXTEMPLATE']][$rs->fields['OXBLOCKNAME']];
00934 } else {
00935 $blStatus = $this->_checkTemplateBlock($rs->fields['OXTEMPLATE'], $rs->fields['OXBLOCKNAME']);
00936 $aCache[$rs->fields['OXTEMPLATE']][$rs->fields['OXBLOCKNAME']] = $blStatus;
00937 }
00938
00939 if (!$blStatus) {
00940 $aRet[] = array(
00941 'module' => $rs->fields['OXMODULE'],
00942 'block' => $rs->fields['OXBLOCKNAME'],
00943 'template' => $rs->fields['OXTEMPLATE'],
00944 );
00945 }
00946 $rs->moveNext();
00947 }
00948 }
00949
00950 return $aRet;
00951 }
00952 }