/** rotate a string, use for simple encoding */ function rotateString($pInput,$pRotateNum=0) { $vOutput = ”; $vStr = ‘abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890|’; $vLen = strlen($vStr); for ($i=0;$i $vIndex = strpos($vStr,$pInput{$i}); if ($vIndex===FALSE) { // non-encode chars, leave these alone $vOutput .= $pInput{$i}; } else { $vIndex = $vIndex+$pRotateNum; $vIndex = $vIndex>0?$vIndex%$vLen:($vLen+$vIndex)%$vLen; $vOutput .= $vStr{$vIndex}; } // fi } // rof //var_dump($vOutput); return $vOutput; }
$a = rotateString($b,19); // encode $b = rotateString($a,-19); // decode
This scripts show the content of a div when clicked on an opener.
if (typeof(document.createElement(‘div’).contains) == ‘undefined’) { /** overwrite this function to avoid firing child event inside a parent */ HTMLElement.prototype.contains = function(node) { if (node == null) return false; if (node == this) return true; else return this.contains(node.parentNode); } } // fi
var $globInPopup = false; var $globTarget; var $globTimerID;
function signalMouseIn($pPopID,$pEvt) { $globInPopup = true; window.clearTimeout($globTimerID); } function closePop($pPopID,$pEvt) { var $vPop = $as($pPopID); if (!$vPop.contains(getTarget($pEvt))) { $globTarget = getTarget($pEvt); $globTimerID = window.setTimeout(“mouseOutPopup(‘”+$pPopID+”‘)”,600); } // if } function mouseOutPopup($pPopID) { var $vPop = $as($pPopID); if (!$vPop.contains($globTarget)) { hidePopup($vPop); } // fi } function trigOpenerOut($pPopID,$pEvt) { $globTarget = getTarget($pEvt); $globTimerID = window.setTimeout(“mouseOutOpener(‘”+$pPopID+”‘)”,600); } function mouseOutOpener($pPopID) { var $vPop = $as($pPopID); if (!$globInPopup && !$vPop.contains($globTarget)) { hidePopup($vPop); } // fi }
function hidePopup($pPop) { $pPop.style.visibility = ‘hidden’; $globInPopup = false; }
function getTarget($pEvent) { if (typeof($pEvent.relatedTarget)!=’undefined’) { return $pEvent.relatedTarget; } else if (typeof($pEvent.toElement)!=’undefined’) { return $pEvent.toElement; } // fi return false; }
function showRelPop($pPopID) { $as($pPopID).style.visibility = ‘visible’; }
This js code extends the tablesorter plugin in jQuery:
Let’s get right into the code:
/** define custom sorter and widgets for tablesorter plugin for jQuery * @since 10/4/2008 * @author Son Nguyen */
// add sorting by 1,300,000 (with commas) $.tablesorter.addParser({ id: “fwnumber”, is: function(s) { return false; }, format: function(s) { return $.tablesorter.formatFloat(s.replace(/(\,|\%)/g,”")); }, type: “numeric” });
// only look for value in the comment, eg: , $.tablesorter.addParser({ id: “commenttxt”, is: function(s) { return /^/.test($.trim(s)); }, format: function(s) { return s.replace(/^.*/g,”$1″); }, type: “text” });
// only look for value in the comment, eg: $.tablesorter.addParser({ id: “commentnum”, is: function(s) { return /^/.test($.trim(s)); }, format: function(s) { return s.replace(/^.*/g,”$1″); }, type: “numeric” });
// show the hover row different than other rows $.tablesorter.addWidget({ id: “rowHover”, format: function(table) { $(“tr:visible”,table.tBodies[0]).hover( function () { $(this).addClass(table.config.widgetRowHover.css); }, function () { $(this).removeClass(table.config.widgetRowHover.css); } ); } });
// apply CSS to the sortable header when mouse hovers it $.tablesorter.addWidget({ id: “headerHover”, format: function(table) { $(“thead th:visible”,table).hover( function () { if (!table.config.headerList[$("thead th:visible",table).index(this)].sortDisabled) $(this).addClass(table.config.widgetHeaderHover.css); }, function () { $(this).removeClass(table.config.widgetHeaderHover.css); } ); } });
// call a link via AJAX to save/memorize the sort order $.tablesorter.addWidget({ id: “memorizeSortOrder”, format: function(table) { if (!table.config.widgetMemorizeSortOrder.isBinded) { // only bind if not already binded table.config.widgetMemorizeSortOrder.isBinded = true; $(“thead th:visible”,table).click(function() { var i = $(“thead th:visible”,table).index(this); $.get(table.config.widgetMemorizeSortOrder.url+i+’|'+table.config.headerList[i].order); }); } // fi } });
Demo HTML file
This PHP 5 class forecasts future values from past data. It takes into account the growth trend, seasonality and irregularity (noise) in input data. This class uses an external class: linear regression analysis
/** A time-series forcasting, given a series of data (w/ seasonal data), predict future data * Src: http://home.ubalt.edu/ntsbarsh/stat-data/Forecast.htm & BUS264 (Oliver Yu's coursenote) * @author Son Nguyen * @since 10/1/2008 * @package Framework * @subpackage Math */ class CMathForecasting { private $mPastDatas; // array of data (eg: x1,x2,x3,x4...) private $mNumSeasons; // the number of seasons to consider (eg: 4 quarters/year, 7 days/week, 24 hours/day) /** constructor */ function __construct($pPastDatas,$pNumSeasons) { $this->mPastDatas = $pPastDatas; $this->mNumSeasons = $pNumSeasons; }
/** compute the n-season moving average */ function computeSMA() { $vSMA = array(); for ($i=0;$imPastDatas);$i++) { if ($i+$this->mNumSeasons-1>=count($this->mPastDatas)) { // out of bound, done break; } // fi
$vSum = 0; for ($j=0;$j<$this->mNumSeasons;$j++) { $vSum += $this->mPastDatas[$i+$j]; } // rof $vSMA[] = $vSum/$this->mNumSeasons; } // rof return $vSMA; }
/** compute centered moving average from the n-season moving average */ function computeCMA($pSMA) { $vCMA = array(); for ($i=0;$i if ($i+1>=count($pSMA)) { // out of bound, done break; } // fi $vCMA[] = ($pSMA[$i]+$pSMA[$i+1])/2; } // rof return $vCMA; }
/** season irregularity */ function computeNoises($pCMA) { $vNoises = array(); for ($i=0;$i $vStarting = floor($this->mNumSeasons/2); $vNoises[] = $this->mPastDatas[$i+$vStarting]/$pCMA[$i]; } // rof return $vNoises; }
/** comment */ function computeSeasonIndices($pNoises) { $vIndices = array(); for ($i=0;$i<$this->mNumSeasons;$i++) { $vSum = array(); for ($j=$i;$jmNumSeasons) { $vSum[] = $pNoises[$j]; } // rof $vStarting = (floor($this->mNumSeasons/2)+$i)%$this->mNumSeasons; $vIndices[$vStarting] = array_sum($vSum)/count($vSum); } // rof
ksort($vIndices);
// also adjust these season indices $vSum = array_sum($vIndices); for ($i=0;$i $vIndices[$i] = $vIndices[$i]*$this->mNumSeasons/$vSum; } // rof return $vIndices; }
/** comment */ function computeDeSeasonalized($pSeasonIndex) { $vDatas = array();
for ($i=0;$imPastDatas);$i++) { $vDatas[] = $this->mPastDatas[$i]/$pSeasonIndex[$i%$this->mNumSeasons]; } // rof return $vDatas; }
/** how many future periods to predict */ function predict($pNumFuturePeriods) { $vSMA = $this->computeSMA(); if ($this->mNumSeasons%2==0) { // even $vCMA = $this->computeCMA($vSMA); } else { // odd, nSMA=CMA $vCMA = $vSMA; } // fi
$vNoises = $this->computeNoises($vCMA); $vIndices = $this->computeSeasonIndices($vNoises);
$vDeSeasonalized = $this->computeDeSeasonalized($vIndices);
// perform regression to get the trend line $vRegression = new CRegressionLinear($vDeSeasonalized); list($vXVar,$vIntercept) = $vRegression->calculate();
$vForecast = array(); for ($i=0;$i<$pNumFuturePeriods;$i++) { $vForecast[] = $vIntercept + $vXVar*(count($this->mPastDatas)+$i); } // rof
// have to re-seasonalized these values for ($i=0;$i $vForecast[$i] = $vForecast[$i]*$vIndices[(count($this->mPastDatas)+$i)%$this->mNumSeasons]; } // rof
return $vForecast;
} } ?>
include('math.reg.linear.class.php'); include('math.forecasting.class.php');
// Example #1: daily sales number for the past 30 days $vSales = array( 637381,700986,641305,660285,604474,565316,598734,688690,723406,697358, 669910,605636,526655,555165,625800,579405,588317,634433,628443,570597, 662584,763516,742150,703209,669883,586504,489240,648875,692212,586509 );
$vForecast = new CMathForecasting($vSales,7); // sales pattern is weekly $vResult = $vForecast->predict(7); // predict the next 7 days var_dump($vResult);
// Example #2: quarterly demand number (x1000 units) $vSales = array( 3,9,6,2, 4,11,8,3, 5,15,11,3 );
$vForecast = new CMathForecasting($vSales,4); // sales pattern is quarterly $vResult = $vForecast->predict(4); // predict the next 4 quarters var_dump($vResult); ?>
With JSONP, you can avoid the “Access is Denied” problem when loading a remote AJAX request. jQuery 1.2.x now supports JSONP, you can use that or this simple code snippet. In this example, let’s assume you’re on a page with a remote javascript loaded, now you only want this remote script to reload, not the whole page.
function reloadJS() { var url = ‘http://example.com/getJSON.php?id=1234′; var js = document.createElement(“script”); js.setAttribute(“src”,url+”&CacheBuster=”+Math.random()); js.setAttribute(“type”,”text/javascript”); document.body.appendChild(js); }
function ajaxJSONCallback(data) { document.getElementById(“SomeDivID”).innerHTML = data.SomeData; }
window.setInterval(“reloadJS()”,10000);
And the result of getJSON.php: ajaxJSONCallback({“SomeData”:” Test Output “});
Test Output
“});
If you need to reload a partial content (not the whole page) with JavaScript, you can easily use AJAX (jQuery is the simplest). But if the content is also from another website (eg: some API), then you can use JSONP (JSON with Padding) to get around the security protection of AJAX requests.
document.write(“ “); document.write(“Initial Contents”); document.write(“ “); function reloadJS() { var js = document.createElement(“script”); js.setAttribute(“src”,”http://example.com/javascript.php?output=jsonp&random=”+Math.random()); js.setAttribute(“type”,”text/javascript”); document.body.appendChild(js); } function ajaxJSONCallback(data) { document.getElementById(“MyContent”).innerHTML = data.FullHTML; } window.setInterval(“reloadJS()”,{ASJSRefreshSec});
“);
function reloadJS() { var js = document.createElement(“script”); js.setAttribute(“src”,”http://example.com/javascript.php?output=jsonp&random=”+Math.random()); js.setAttribute(“type”,”text/javascript”); document.body.appendChild(js); }
function ajaxJSONCallback(data) { document.getElementById(“MyContent”).innerHTML = data.FullHTML; } window.setInterval(“reloadJS()”,{ASJSRefreshSec});
And in the server-side javascript.php, you would return: ajaxJSONCallback({‘FullHTML’:'New Content’})
/** grid sorting class * @since 3/29/2005 * @author Son Nguyen * @package Scripts * @subpackage Grid */ function CGridSort($pTableID) { this.mTable = $($pTableID); this.mSortOrder = null; // asc=0, desc=1 this.mColumnIndex = null; // which is the actively sorted col this.mShouldBeOrder = null; // the correct order after sorted this.mCurrentOrder = null; // the current row order
this.mBodyOnClass = null; // mouse over row style this.mBodyOffClass = null; this.mHeaderOnClass = null; // mouse over header style this.mHeaderOffClass = null; this.mHeaderUpClass = null; // header sorted up this.mHeaderDownClass = null;
var $vRows = this.mTable.rows; for (var $i=1;$i<$vRows.length;$i++) { // assumption: 1st row is header! Skip! if ($vRows[$i].nodeName == 'TR') { var oThis = this; $vRows[$i].onmouseover = function () { oThis.highLiteRow(this) }; $vRows[$i].onmouseout = function () { oThis.highLiteRow(this) }; } // fi } // rof }
CGridSort.prototype.setBodyClass = function($pOn,$pOff) { this.mBodyOnClass = $pOn; this.mBodyOffClass = $pOff; }
CGridSort.prototype.setHeaderClass = function($pOn,$pOff,$pUp,$pDown) { this.mHeaderOnClass = $pOn; this.mHeaderOffClass = $pOff; this.mHeaderUpClass = $pUp; this.mHeaderDownClass = $pDown; }
CGridSort.prototype.highLiteRow = function($pRowObj) { var $vCSS = new CElementCSS($pRowObj); if ($vCSS.hasStyle(this.mBodyOnClass)) { $vCSS.removeStyle(this.mBodyOnClass); $vCSS.appendStyle(this.mBodyOffClass); } else { $vCSS.removeStyle(this.mBodyOffClass); $vCSS.appendStyle(this.mBodyOnClass); } // fi }
CGridSort.prototype.showSrtOrd = function($pHeaderCell,$pIsHeaderOn) { this.clearOrders($pHeaderCell); var $pPrimary = ($pIsHeaderOn==true)?this.mHeaderOnClass:this.mHeaderOffClass;
if ($pHeaderCell.cellIndex==this.mColumnIndex && this.mSortOrder==0) { $pHeaderCell.className = $pPrimary+' '+this.mHeaderUpClass; } else if ($pHeaderCell.cellIndex==this.mColumnIndex && this.mSortOrder==1) { $pHeaderCell.className = $pPrimary+' '+this.mHeaderDownClass; } else { $pHeaderCell.className = $pPrimary; } // fi } /** clear orders for other headers */ CGridSort.prototype.clearOrders = function($pHeaderCell) { var $vHeaders = $pHeaderCell.parentNode.childNodes; for (var $i=0;$i<$vHeaders.length;$i++) { if ($vHeaders[$i].nodeName=='TH' && $i!=this.mColumnIndex && $vHeaders[$i] != $pHeaderCell) { $vHeaders[$i].className = this.mHeaderOffClass; } // fi } // rof }
/** actually do the sorting */ CGridSort.prototype.sortCol = function($pColumnIndex) { this.mSortOrder = (this.mSortOrder!=null && $pColumnIndex==this.mColumnIndex)?(this.mSortOrder+1)%2:0; this.mColumnIndex = $pColumnIndex;
this.initSort();
// swap those not in place for (var $i=0;$i if (this.mCurrentOrder[$i]!=this.mShouldBeOrder[this.mColumnIndex][$i]) { this.swapRow(this.mCurrentOrder[$i],this.mShouldBeOrder[this.mColumnIndex][$i]); } // fi } // rof
// reverse the order array this.mShouldBeOrder[this.mColumnIndex].reverse(); }
/** init the global vars, done for every col for the first time */ CGridSort.prototype.initSort = function() { // init gRows for this table if not done outside already if (this.mCurrentOrder==null) { this.mCurrentOrder = new Array(); var $vLength = 0; var $vCnt = 0; var $vRows = this.mTable.rows; for (var $i=1;$i<$vRows.length;$i++) { // assumption: 1st row is header! Skip! if ($vRows[$i].nodeName == 'TR') { this.mCurrentOrder[this.mCurrentOrder.length] = $vRows[$i].id; } // fi } // rof } // fi
// init order-by array if (this.mShouldBeOrder==null) { this.mShouldBeOrder = new Array(); } if (typeof(this.mShouldBeOrder[this.mColumnIndex])=='undefined') { this.mShouldBeOrder[this.mColumnIndex] = new Array(); var $vTmpAry = new Array(); var $vTmpAry2 = new Array(); var $vCellValue = null; var $vKey = null; var $vSampleValue = null; for (var $i=0;$i $vCellValue = this.processSortValue($(this.mCurrentOrder[$i]).cells[this.mColumnIndex].innerHTML); if ($vCellValue!='') { $vSampleValue = $vCellValue; } // if $vTmpAry[$i] = $vCellValue;
$vKey = $vCellValue; while (typeof($vTmpAry2[$vKey])!='undefined') { $vKey = $vKey+'x'; } // rof $vTmpAry2[$vKey] = this.mCurrentOrder[$i]; } // rof
// determine sort algorithm and sorting var $vSortFn = null; // this.sortCaseInsen; // default, use the internally supported, the other give IE "Number Expected" err if ($vSampleValue.match(/^\d\d[\/-]\d\d[\/-]\d\d\d\d$/)) $vSortFn = this.sortDate; if ($vSampleValue.match(/^\d\d[\/-]\d\d[\/-]\d\d$/)) $vSortFn = this.sortDate; if ($vSampleValue.match(/^[£$]/)) $vSortFn = this.sortCur; if ($vSampleValue.match(/^[\d\.\,\%]+$/)) $vSortFn = this.sortNum; //alert($vSortFn); if ($vSortFn!=null) { $vTmpAry.sort($vSortFn); } else { $vTmpAry.sort(); } // fi
//alert('pass sorting');
// correct the duplicate rows for (var $i=0;$i<$vTmpAry.length;$i++) { for (var $j=$i+1;$j<$vTmpAry.length;$j++) { if ($vTmpAry[$i]==$vTmpAry[$j]) { $vTmpAry[$j] = $vTmpAry[$j]+'x'; } else { // break out of the first loop now, save some time break; } // fi } // rof } // rof
var $vRowID = null; for (var $i=0;$i<$vTmpAry.length;$i++) { $vRowID = $vTmpAry2[$vTmpAry[$i]]; this.mShouldBeOrder[this.mColumnIndex][$i] = $vRowID; } // rof } // fi }
/** swapping data and index */ CGridSort.prototype.swapRow = function($pRowA,$pRowB) { var $vOne = $($pRowA); var $vTwo = $($pRowB); var $vTmp;
// 1.3 swap the data for (var $k=0;$k<$vOne.cells.length;$k++) { $vTmp = $vOne.cells[$k].innerHTML; $vOne.cells[$k].innerHTML = $vTwo.cells[$k].innerHTML; $vTwo.cells[$k].innerHTML = $vTmp; } // for
// 2.3 also swap index for (var $k=0;$k if (this.mCurrentOrder[$k] == $pRowA) { this.mCurrentOrder[$k] = $pRowB; } else if (this.mCurrentOrder[$k] == $pRowB) { this.mCurrentOrder[$k] = $pRowA; } // else } // for
// 3.3 also swap id $vOne.id = $pRowB; $vTwo.id = $pRowA; }
/** strip tags, process special comment for timestamp/other special cases */ CGridSort.prototype.processSortValue = function($pValue) { var $vResult = $pValue.match(//g); if ($vResult) { // comment stores the real value, ignore the outside $pValue = $vResult[0]; $pValue = $pValue.substring(4,$pValue.length-4); $pValue = $pValue.replace(/ /g,”); } else { // strip tags or everything within tags var $vBkup = $pValue; // first try to strip everything between a pair of tags $pValue = $pValue.replace(/<[^>]+>/g,’<>‘); // anything in <> $pValue = $pValue.replace(/<>.*<>/g,”); $pValue = $pValue.replace(/<>/g,”); if ($pValue==”) { // then only strip tags, leave everything in between $pValue = $vBkup.replace(/<[^>]+>/g,”); } // fi $pValue = $pValue.replace(/^\s*|\s*$/g,”); // whitespaces $pValue = $pValue.replace(/ /g,”); $pValue = $pValue.replace(/ /g,”); $pValue = $pValue.replace(/\n/g,”); } // fi return $pValue; }
/** HELPER, SORT FUNCTIONS */
/** sort case insensitive */ CGridSort.prototype.sortCaseInsen = function($pValueA,$pValueB) { $pValueA = $pValueA.toLowerCase(); $pValueB = $pValueB.toLowerCase();
if ($pValueA>$pValueB) return 1; if ($pValueA<$pValueB) return -1; return 0; }
CGridSort.prototype.sortNum = function($pValueA,$pValueB) { $pValueA = parseFloat($pValueA.replace(/[^0-9.]/g,'')); $pValueB = parseFloat($pValueB.replace(/[^0-9.]/g,''));
if (isNaN($pValueA)) $pValueA = 0; if (isNaN($pValueB)) $pValueB = 0;
return $pValueA-$pValueB; }
/** sort on date */ CGridSort.prototype.sortDate = function($pValueA,$pValueB) { if ($pValueA.length == 10) { $dt1 = $pValueA.substr(6,4)+$pValueA.substr(3,2)+$pValueA.substr(0,2); } else { $yr = $pValueA.substr(6,2); if (parseInt($yr) < 50) { $yr = '20'+$yr; } else { $yr = '19'+$yr; } $dt1 = $yr+$pValueA.substr(3,2)+$pValueA.substr(0,2); } // if
if ($pValueB.length == 10) { $dt2 = $pValueB.substr(6,4)+$pValueB.substr(3,2)+$pValueB.substr(0,2); } else { $yr = $pValueB.substr(6,2); if (parseInt($yr) < 50) { $yr = '20'+$yr; } else { $yr = '19'+$yr; } $dt2 = $yr+$pValueB.substr(3,2)+$pValueB.substr(0,2); } if ($dt1==$dt2) return 0; if ($dt1<$dt2) return -1; return 1; }
/** sort currency */ CGridSort.prototype.sortCur = function($pValueA,$pValueB) { $pValueA = $pValueA.replace(/[^0-9.]/g,''); $pValueB = $pValueB.replace(/[^0-9.]/g,''); return parseFloat($pValueA) - parseFloat($pValueB); }
Given a content string, this class uses Yahoo Term Extraction API to generate a list of keywords/phrases that you can use for things like META tags or other SEO objectives.
/** * @author Son Nguyen * @since 2/13/2006 * @package Framework * @subpackage WebServices */ class CYahooTermExtraction extends CYahooAPI { private $mContext; // string, get main keywords from this text /** constructor */ function __construct($pContext) { $this->mServiceURL = ‘http://api.search.yahoo.com/ContentAnalysisService/V1/termExtraction’; $this->mContext = $pContext; }
/** get the tags/keywords through Yahoo API */ function fetchTags() { $vReq = new CHTTPRequest($this->mServiceURL); $vReq->addQueryString(‘appid’,$this->mAppID); $vReq->addQueryString(‘context’,$this->mContext); list($vHeader,$vBody) = $vReq->sendPOST(); //var_dump($vHeader,$vBody);die; $vXML = simplexml_load_string($vBody); $vTmp = array(); foreach ($vXML->Result AS $vOne) { $vTmp[] = (string)$vOne; } // rof return $vTmp; // an array of tags }
/** comment */ function display() { $vTags = $this->fetchTags(); return implode(‘, ‘,$vTags); } } ?>
/** * @author Son Nguyen * @since 3/21/2006 * @package Framework * @subpackage WebServices */ class CYahooAPI { protected $mAppID = 'YourYahooApplicationID'; protected $mServiceURL;
/** constructor */ function __construct() {
This class parses, fixes and prepares php_browscap.ini into browscap.ini for PHP. It also detects if the latest version needed to download.
/** from localhost to fetch and prepare the browscap.ini file * @author Son Nguyen * @since 8/25/2006 * @package Framework * @subpackage Lookup */ class CBrowsCap { private $mTmpFileName = 'php_browscap.ini'; // tmp file before fixing private $mDownloadURL = 'http://browsers.garykeith.com/stream.asp?PHP_BrowsCapINI'; /** constructor */ function __construct() {}
/** get the version string from the file */ function getVersion($pFile,$pCheckExisted) { $vVersion = NULL; if ($pCheckExisted && !file_exists($pFile)) { return NULL; } // fi
$vContent = file_get_contents($pFile,FALSE,NULL,0,500); if (preg_match('/version=(.*)/i',$vContent,$vMatches)) { $vVersion = trim($vMatches[1]); } // fi return $vVersion; }
/** comment */ function getLatestVersion() { return $this->getVersion($this->mDownloadURL,FALSE); }
/** get the current I’m currently use */ function getMyVersion() { return $this->getVersion($this->mTmpFileName,TRUE); }
/** if need to update */ function checkUpdate() { $vMy = $this->getMyVersion(); $vLatest = $this->getLatestVersion(); if (!file_exists($this->mTmpFileName) || $vMy<$vLatest) { // should update $vContent = file_get_contents($this->mDownloadURL); file_put_contents($this->mTmpFileName,$vContent); return ‘Updated to version #’.$vLatest.’ from #’.$vMy; // yes, do update } // fi
return ‘Already at the latest version #’.$vLatest; // latest, don’t update }
/** fix the browsecap.ini for php */ function fix() { $vOutput = $this->checkUpdate();
$vContent = file_get_contents($this->mTmpFileName); $vContent = preg_replace(“/\r/”,”",$vContent); $vContent = preg_replace(‘/=”(.*)”/i’,'=\\1′,$vContent); $vContent = preg_replace(“/platform=(.*)/i”,”platform=\”\\1\”",$vContent); $vContent = preg_replace(“/parent=(.*)/i”,”parent=\”\\1\”",$vContent); $vContent = preg_replace(“/minorver=(.*)/i”,”minorver=\”\\1\”",$vContent); $vContent = preg_replace(“/majorver=(.*)/i”,”majorver=\”\\1\”",$vContent); $vContent = preg_replace(“/version=(.*)/i”,”version=\”\\1\”",$vContent); $vContent = preg_replace(“/browser=(.*)/i”,”browser=\”\\1\”",$vContent); $vContent = str_replace(“[*]“,”*”,$vContent); file_put_contents(‘browscap.ini’,$vContent);
return $vOutput; } } ?>
Developers can use the browscap.ini to detect if the User-Agent is a search engine or data collection spider or not. However, that file is rather large and will be expensive on resources. If you need a faster, simpler (albeit less accurate) method, this class can be useful.
/** a quick/less resource intensive browser detection * @author Son Nguyen * @since 1/29/2007 * @package Framework * @subpackage Misc */ class CBrowserDetect { private $mUA; /** constructor */ function __construct($pUA=NULL) { $this->setUA($pUA); }
/** comment */ function setUA($pUA=NULL) { if (is_null($pUA) && isset($_SERVER['HTTP_USER_AGENT'])) { $this->mUA = $_SERVER['HTTP_USER_AGENT']; } else { $this->mUA = $pUA; } // fi }
/** if this is a spider/crawler */ function isSpider($pUA=NULL) { $this->setUA($pUA); $vBots = array( ‘AdsBot-Google’, ‘alexa’, ‘appie’, ‘Ask Jeeves’, ‘Baiduspider’, ‘crawler’, ‘FAST’, ‘Firefly’, ‘froogle’, ‘girafabot’, ‘Googlebot’, ‘ia_archiver’, ‘InfoSeek’, ‘inktomi’, ‘Java/’, ‘looksmart’, ‘msnbot’, ‘NationalDirectory’, ‘rabaz’, ‘Scooter’, ‘Slurp’, ‘Spade’, ‘TECNOSEEK’, ‘Teoma’, ‘URL_Spider_SQL’, ‘WebBug’, ‘WebCapture’, ‘WebFindBot’, ‘Wget/’, ‘ZyBorg’, ‘libwww-perl/’, ‘httpunit/’, ‘WebZIP/’, ); foreach ($vBots AS $vPat) { if (stripos($this->mUA,$vPat)!==FALSE) { return TRUE; } // fi } // rof return FALSE; } } ?>