Retrieve the country code in PHP - php

I'm a little lost with that.
How can I retrieve the ISO country code of the visitors at one php page?
Thanks advance

You can either do this by Geolocation of the IP or by inspecting the right headers.
Usually you want the latter, since it tells you which languages the browser/system uses. You will only want to use geolocation when you want to know the physical location.
The header is stored in $_SERVER['HTTP_ACCEPT_LANGUAGE']. It contains comma-separated entries, e.g.: en-GB,en;q=0.8,en-US;q=0.6,nl;q=0.4 (my own)
The HTTP Accept Language parameters seperates it's languages by a comma, it's properties by a semicolon. The q-value is from 0 to 1, with 1 being the highest/most preferred. Here is some naive and untested code to parse it:
$langs = explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']);
$preffered = "";
$prefvalue = 0;
foreach($langs as $lang){
$info = explode(';', $lang);
$val = (isset($lang[1])?$lang[1];1);
if($prefvalue < $val){
$preferred = $lang[0];
$prefvalue = $val;
}
}
Much simpler is it if you want to test if a specific language is accepted, e.g. Spanish (es):
if(strpos($_SERVER['HTTP_ACCEPT_LANGUAGE'], "es") !== false){
// Spanish is supported
}

I think you could use this php script which uses an ip and prints out a country code
Example
http://api.hostip.info/country.php?ip=4.2.2.2
Gives US
Check out
http://www.hostip.info/use.html
for more info.

A library i use myself and can recommend, is MaxMind GeoLite Country. To get the country code, you need only to copy 2 files to your server, the php code geoip.inc and the binary data GeoIP.dat.
Using the library is also very straightforward:
function ipToCountry()
{
include_once('geoip/geoip.inc');
$gi = geoip_open(__DIR__ . '/geoip/GeoIP.dat', GEOIP_STANDARD);
$result = geoip_country_code_by_addr($gi, $_SERVER['REMOTE_ADDR']);
geoip_close($gi);
return $result;
}

This will use GeoIp and fall back to accept_lang
class Ip2Country
{
function get( $target )
{
$country = false;
if( function_exists( 'geoip_record_by_name' ) )
$country = $this->getFromIp( $target );
if( !$country && isset( $_SERVER['HTTP_ACCEPT_LANGUAGE'] ) )
$country = $this->getFromLang( $_SERVER['HTTP_ACCEPT_LANGUAGE'] );
return $country;
}
function getFromIp( $target )
{
$dat = #geoip_record_by_name( $target );
return ( isset( $dat['country_code'] ) ) ? mb_strtolower( $dat['country_code'] ) : false;
}
function getFromLang( $str )
{
$info = array();
$langs = explode( ',', $str );
foreach( $langs as $lang )
{
$i = explode( ';', $lang );
$j = array();
if( !isset( $i[0] ) ) continue;
$j['code'] = $i[0];
if( strstr( $j['code'], '-' ) )
{
$parts = explode( '-', $j['code'] );
$j['lang'] = $parts[0];
$j['country'] = mb_strtolower( $parts[1] );
}
$info[] = $j;
}
return ( isset( $info[0]['country'] ) ) ? $info[0]['country'] : false;
}
}
$x = new Ip2Country();
var_dump( $x->get( 'canada.ca' ) );

Related

Is it possible to know the origin of SoapClient request?

I need to use the SoapClient PHP function to use a service from another site that will give me a certain information.
Can they know from what site came that request?
Thank you all.
Yes, if you put this code (example)
function get_base_domain_by_name ( $name ) {
if (is_string($name) && preg_match('/^[a-z0-9\-\.]+\.[a-z0-9\-]+$/i', $name) === 1) {
$parts = array_reverse(explode('.', strtolower($name)));
$base = array_shift($parts);
foreach ($parts as $part ) {
$base = $part.'.'.$base;
if (( $addr = gethostbyname($base) ) != $base && preg_match('/^[0-9\.]+$/', $addr) === 1 ) {
return($base);
}
}
}
return(false);
}
function get_base_domain_by_addr ( $addr ) {
return(get_base_domain_by_name(gethostbyaddr($addr)));
}
$domain = get_base_domain_by_addr($_SERVER['REMOTE_ADDR']);
echo $domain;
You can get the URL of the of the Site that accessed you, and if you use: $_SERVER['REMOTE_ADDR'] you can get the IP Address.

php Read file content to a static array

I am writing a code for Bayesian Filter. For a particular word, I want to check if the word is in the stop words list or not, I populate from stop word list from a file on my pc.
Because I have to do this for many words I don't want to read the StopWord file from my pc again and again.
I want to do something like this
function isStopWord( $word ){
if(!isset($stopWordDict))
{
$stopWords = array();
$handle = fopen("StopWords.txt", "r");
if( $handle )
{
while( ( $buffer = fgets( $handle ) ) != false )
{
$stopWords[] = trim( $buffer );
}
}
echo "StopWord opened";
static $stopWordDict = array();
foreach( $stopWords as $stopWord )
$stopWordDict[$stopWord] = 1;
}
if( array_key_exists( $word, $stopWordDict ) )
return true;
else
return false;
}
I thought by using a static variable it will solve the issue, but it doesn't. Kindly help.
Put the static declaration at the beginning of the function:
function isStopWord( $word ){
static $stopWordDict = array();
if(!$stopWordDict)
{
$stopWords = file("StopWords.txt");
echo "StopWord opened";
foreach( $stopWords as $stopWord ) {
$stopWordDict[trim($stopWord)] = 1;
}
}
if( array_key_exists( $word, $stopWordDict ) )
return true;
else
return false;
}
This will work since an empty array is considered falsy.

turning this trainwreck of a function into a recursive one

I've been trying to build this recursive function for the better part of a day now, but I just can't seem to get it to work the way I want.
First, I have a property which holds some data that the function have to access:
$this->data
And then I have this string which the intention is to turn into a relative path:
$path = 'path.to.%id%-%folder%.containing.%info%';
The part of the string that are like this: %value% will load some dynamic values found in the $this->data property (like so: $this->data['id']; or $this->data['folder'];
and to make things really interesting, the property can reference itself again like so: $this->data['folder'] = 'foldername.%subfolder%'; and also have two %values% separated by a - that would have to be left alone.
So to the problem, I've been trying to make a recursive function that will load the dynamic values from the data property, and then again if the new value contains another %value% and so on until no more %value%'s are loaded.
So far, this is what I've been able to come up with:
public function recursiveFolder( $folder, $pathArr = null )
{
$newPathArr = explode( '.', $folder );
if ( count ( $newPathArr ) !== 1 )
{
foreach( $newPathArr as $id => $folder )
{
$value = $this->recursiveFolder( $folder, $newPathArr );
$resultArr = explode( '.', $value );
if ( count ( $resultArr ) !== 1 )
{
foreach ( $resultArr as $nid => $result )
{
$nvalue = $this->recursiveFolder( $result, $newPathArr );
$resultArr[$nid] = $nvalue;
}
}
$resultArr = implode( '.',$resultArr );
$newPathArr[$id] = $resultArr;
}
}
else
{
$pattern = '/%(.*?)%/si';
preg_match_all( $pattern, $folder, $matches );
if ( empty( $matches[0] ) )
{
return $folder;
}
foreach ( $matches[1] as $mid => $match )
{
if ( isset( $this->data[$match] ) && $this->data[$match] != '' )
{
$folder = str_replace( $matches[0][$mid], $this->data[$match], $folder );
return $folder;
}
}
}
return $newPathArr;
}
Unfortunately it is not a recursive function at all as it grinds to a halt when it has multiple layers of %values%, but works with two layers -barely-. (I just coded it so that it would work at a bare minimalistic level this point).
Here's how it should work:
It should turn:
'files.%folder%.blog-%type%.and.%time%'
into:
'files.foldername.blog-post.and.2013.feb-12th.09'
based on this:
$data['folder'] = 'foldername';
$data['type'] = 'post';
$data['time'] = '%year%.%month%-%day%';
$data['year'] = 2013;
$data['month'] = 'feb';
$data['day'] = '12th.%hour%';
$data['hour'] = '09';
Hope you can help!
Jay
I don't see the need for this too be solved recursively:
<?php
function putData($str, $data)
{
// Repeat the replacing process until no more matches are found:
while (preg_match("/%(.*?)%/si", $str, $matches))
{
// Use $matches to make your replaces
}
return $str;
}
?>

Determing the namespace in a mediawiki page (api quest.)

For starters I must admit my PHP skills are pathetic (been doing this for 3 days)
I have during the last three days heavily modified an extension which parses pages just edited in mediawiki. The original purpose was to parse the page for text matching the names of other pages in the database, and autolink them. But it would only perform this function in the 'Main' namespace (namespace 0). I have modified it to parse for links across namespaces, using a weighted White-List of namespaces. (Weighted as in first come first serve based on the location in the white list. If white list is Development, Rules the Development trumps rules.)
I would like to further modify the extension to prioritize the current page's namespace by pushing it onto the front of the white list array, and to determine the current users group affiliations so as to further modify the priority list.
Determine the users group affiliations
Determine the current page's namespace SOLVED $var=$article->getTitle()->getNamespace();
Push the value to the front of the array SOLVED array_unshift($hastack, $needle);
I would greatly appreciate it if someone could point me to a site explaining at least the first two things. (The mediawiki community has thus far been less than useful)
If you offer up a code example please try to keep it stupidproof, I am that new to this {{shrug}} (Meaning keep the code samples php simple...it's extensible so there is always a better way, but I am not familiar with the extra modules.)
MediaWiki version in question is 1.21 (current stable as of 7-2013)
NOTE: For some reason the code isn't displaying right, but no lines were lost.
The array for the whitelist is defined as:
$wgLinkTitlesNamespaceWhitelist = array(5000, 5002, 5004, 5006,0);
Main file LinkTitles5000_body,php
if ( !defined( 'MEDIAWIKI' ) ) {
die( 'Not an entry point.' );
}
/*
function dump($var) {
error_log(print_r($var, TRUE) . "\n", 3, 'php://stderr');
};
*/
class LinkTitles_5000 {
static $safeTitle;
/// Setup function, hooks the extension's functions to MediaWiki events.
public static function setup() {
global $wgLinkTitlesParseOnEdit;
global $wgLinkTitlesParseOnRender;
global $wgHooks;
if ( $wgLinkTitlesParseOnEdit ) {
$wgHooks['ArticleSave'][] = 'LinkTitles_5000::onArticleSave';
};
if ( $wgLinkTitlesParseOnRender ) {
$wgHooks['ArticleAfterFetchContent'][] = 'LinkTitles_5000::onArticleAfterFetchContent';
};
$wgHooks['ParserBeforeTidy'][] = 'LinkTitles_5000::removeMagicWord';
}
/// This function is hooked to the ArticleSave event.
/// It will be called whenever a page is about to be
/// saved.
public static function onArticleSave( &$article, &$user, &$text, &$summary,
$minor, $watchthis, $sectionanchor, &$flags, &$status ) {
// To prevent time-consuming parsing of the page whenever
// it is edited and saved, we only parse it if the flag
// 'minor edits' is not set.
return $minor or self::parseContent( $article, $text );
}
/// Called when an ArticleAfterFetchContent event occurs; this requires the
/// $wgLinkTitlesParseOnRender option to be set to 'true'
public static function onArticleAfterFetchContent( &$article, &$content ) {
// The ArticleAfterFetchContent event is triggered whenever page content
// is retrieved from the database, i.e. also for editing etc.
// Therefore we access the global $action variabl to only parse the
// content when the page is viewed.
global $action;
if ( in_array( $action, array('view', 'render', 'purge') ) ) {
self::parseContent( $article, $content );
};
return true;
}
/// This function performs the actual parsing of the content.
static function parseContent( &$article, &$text ) {
// If the page contains the magic word '__NOAUTOLINKS__', do not parse
// the content.
$mw = MagicWord::get('MAG_LINKTITLES_TERMINOLOGY_NOAUTOLINKS');
if ( $mw -> match( $text ) ) {
return true;
}
// Configuration variables need to be defined here as globals.
global $wgLinkTitlesPreferShortTitles;
global $wgLinkTitlesMinimumTitleLength;
global $wgLinkTitlesParseHeadings;
global $wgLinkTitlesBlackList;
global $wgLinkTitlesSkipTemplates;
global $wgLinkTitlesFirstOnly;
global $wgLinkTitlesWordStartOnly;
global $wgLinkTitlesWordEndOnly;
// global $wgLinkTitlesIgnoreCase;
global $wgLinkTitlesSmartMode;
global $wgCapitalLinks;
global $wgLinkTitlesNamespaceWhitelist;
global $wgExtraNamespaces;
( $wgLinkTitlesWordStartOnly ) ? $wordStartDelim = '\b' : $wordStartDelim = '';
( $wgLinkTitlesWordEndOnly ) ? $wordEndDelim = '\b' : $wordEndDelim = '';
// ( $wgLinkTitlesIgnoreCase ) ? $regexModifier = 'i' : $regexModifier = '';
// To prevent adding self-references, we now
// extract the current page's title.
$myTitle = $article->getTitle()->getText();
( $wgLinkTitlesPreferShortTitles ) ? $sort_order = 'ASC' : $sort_order = 'DESC';
( $wgLinkTitlesFirstOnly ) ? $limit = 1 : $limit = -1;
if ( $wgLinkTitlesSkipTemplates )
{
$templatesDelimiter = '{{.+}}';
} else {
$templatesDelimiter = '{{[^|]+?}}|{{.+\|';
};
// Build a regular expression that will capture existing wiki links ("[[...]]"),
// wiki headings ("= ... =", "== ... ==" etc.),
// urls ("http://example.com", "[http://example.com]", "[http://example.com Description]",
// and email addresses ("mail#example.com").
// Since there is a user option to skip headings, we make this part of the expression
// optional. Note that in order to use preg_split(), it is important to have only one
// capturing subpattern (which precludes the use of conditional subpatterns).
( $wgLinkTitlesParseHeadings ) ? $delimiter = '' : $delimiter = '=+.+?=+|';
$urlPattern = '[a-z]+?\:\/\/(?:\S+\.)+\S+(?:\/.*)?';
$delimiter = '/(' . $delimiter . '\[\[.*?\]\]|' . $templatesDelimiter .
'|\[' . $urlPattern . '\s.+?\]|'. $urlPattern .
'(?=\s|$)|(?<=\b)\S+\#(?:\S+\.)+\S+(?=\b))/i';
$black_list = str_replace( '_', ' ',
'("' . implode( '", "',$wgLinkTitlesBlackList ) . '")' );
// Depending on the global setting $wgCapitalLinks, we need
// different callback functions further down.
if ( $wgCapitalLinks ) {
$callBack = "LinkTitles_5000::CallBackCaseInsensitive";
} else {
$callBack = "LinkTitles_5000::CallBackCaseSensitive";
}
# Added to suuport $wgLinkTitlesNamespaceWhitelist
foreach ($wgLinkTitlesNamespaceWhitelist as $LT_namespace){
# Create the link part reflecting NameSpace:
# if namespace is main (0) set to empty string
if ($LT_namespace === 0){
$LT_namespacePart = "";
} else {
$LT_namespacePart = str_replace('_', ' ', $wgExtraNamespaces[(int)$LT_namespace]);
$LT_namespacePart = $LT_namespacePart . ":";
}
# ===
// Build an SQL query and fetch all page titles ordered
// by length from shortest to longest.
// Only titles from 'normal' pages (namespace uid = 0)
// are returned.
$dbr = wfGetDB( DB_SLAVE );
# modified to suuport $wgLinkTitlesNamespaceWhitelist
# 'page_namespace = 0' becomes 'page_namespace = ' . $LT_namespace,
# ===
$res = $dbr->select(
$wgDBprefix . 'page',
'page_title, page_namespace',
array(
'page_namespace = ' . strval($LT_namespace),
'CHAR_LENGTH(page_title) >= ' . $wgLinkTitlesMinimumTitleLength,
'page_title NOT IN ' . $black_list,
),
__METHOD__,
array( 'ORDER BY' => 'CHAR_LENGTH(page_title) ' . $sort_order )
);
// Iterate through the page titles
foreach( $res as $row ) {
// Page titles are stored in the database with spaces
// replaced by underscores. Therefore we now convert
// the underscores back to spaces.
$title = str_replace('_', ' ', $row->page_title);
if ( $title != $myTitle ) {
LinkTitles_5000::$safeTitle = str_replace( '/', '\/', $title );
# add this to skip the function if more than 1 level of sub pages
# Thus if 0 or 1 "\/" is found we continue and process the entry
# if two or more are found we go AARRRRRGGGGHHHHH and skip it!
if (substr_count(LinkTitles_5000::$safeTitle, '\/') >1) {
continue;
}
# adding this to allow for sub pages to be broken into their parts
$LT5000_pos = strpos(LinkTitles_5000::$safeTitle, "\/");
if ($LT5000_pos !== false){
$LT5000_front = substr(LinkTitles_5000::$safeTitle, 0, $LT5000_pos);
$LT5000_back = substr(LinkTitles_5000::$safeTitle, $LT5000_pos+1);
LinkTitles_5000::$safeTitle = substr($title, $LT5000_pos+1);
} else {
$LT5000_back = '';
$LT5000_front = LinkTitles_5000::$safeTitle;;
}
// split the string by [[...]] groups
// credits to inhan # StackOverflow for suggesting preg_split
// see http://stackoverflow.com/questions/10672286
$arr = preg_split( $delimiter, $text, -1, PREG_SPLIT_DELIM_CAPTURE );
// Depending on the global configuration setting $wgCapitalLinks,
// the title has to be searched for either in a strictly case-sensitive
// way, or in a 'fuzzy' way where the first letter of the title may
// be either case.
if ( $wgCapitalLinks ) {
$searchTerm = '((?i)' . LinkTitles_5000::$safeTitle[0] . '(?-i)' .
substr(LinkTitles_5000::$safeTitle, 1) . ')';
} else {
$searchTerm = '(' . LinkTitles_5000::$safeTitle . ')';
}
$LT5000_out = "[[" . $LT_namespacePart . $title . "|";
for ( $i = 0; $i < count( $arr ); $i+=2 ) {
// even indexes will point to text that is not enclosed by brackets
$arr[$i] = preg_replace( '/(?<![\:\.\#\/\?\&])' .
$wordStartDelim . $searchTerm . $wordEndDelim . '/',
$LT5000_out.'$1]]', $arr[$i], $limit, $count );
if (( $limit >= 0 ) && ( $count > 0 )) {
break;
};
};
$text = implode( '', $arr );
// If smart mode is turned on, the extension will perform a second
// pass on the page and add links with aliases where the case does
// not match.
if ($wgLinkTitlesSmartMode) {
// split the string by [[...]] groups
// credits to inhan # StackOverflow for suggesting preg_split
// see http://stackoverflow.com/questions/10672286
$arr = preg_split( $delimiter, $text, -1, PREG_SPLIT_DELIM_CAPTURE );
for ( $i = 0; $i < count( $arr ); $i+=2 ) {
// even indexes will point to text that is not enclosed by brackets
$arr[$i] = preg_replace_callback( '/(?<![\:\.\#\/\?\&])' .
$wordStartDelim . '(' . LinkTitles_5000::$safeTitle . ')' .
$wordEndDelim . '/i', $callBack, $arr[$i], $limit, $count );
if (( $limit >= 0 ) && ( $count > 0 )) {
break;
};
};
$text = implode( '', $arr );
}
}; // if $title != $myTitle
}; // foreach $res as $row
}; // foreach $wgLinkTitlesNamespaceWhitelist as $LT_namespace
return true;
}
static function CallBackCaseInsensitive($matches) {
if ($LT5000_pos !== false){
# this if a / was found in the first place
$LT5000_call_out = $LT_namespacePart . $LT5000_front . '/' . $LT5000_back;
} else {
# this if there was no slash
$LT5000_call_out = $LT_namespacePart . $matches[0];
}
if ( strcmp(substr(LinkTitles_5000::$safeTitle, 1), substr($matches[0], 1)) == 0 ) {
return '[[' . $LT5000_call_out . '|]]';
} else {
return '[[' . $LT5000_call_out . '|' . $matches[0] . ']]';
}
}
static function CallBackCaseSensitive($matches) {
if ($LT5000_pos !== false){
# this if a / was found in the first place
$LT5000_call_out = $LT_namespacePart . $LT5000_front . '/' . $LT5000_back;
} else {
# this if there was no slash
$LT5000_call_out = $LT_namespacePart . $matches[0];
}
if ( strcmp(substr(LinkTitles_5000::$safeTitle, 0), substr($matches[0], 0)) == 0 ) {
return '[['. $LT5000_call_out . '|]]';
} else {
return '[[' . $LT5000_call_out . '|' . $matches[0] . ']]';
}
}
static function removeMagicWord( &$parser, &$text ) {
$mw = MagicWord::get('MAG_LINKTITLES_TERMINOLOGY_NOAUTOLINKS');
$mw -> matchAndRemove( $text );
return true;
}
}
And the modules loader function LinkTitles_5000.php:
if ( !defined( 'MEDIAWIKI' ) ) {
die( 'Not an entry point.' );
}
/*
error_reporting(E_ALL);
ini_set('display_errors', 'On');
ini_set('error_log', 'php://stderr');
$wgMainCacheType = CACHE_NONE;
$wgCacheDirectory = false;
*/
// Configuration variables
$wgLinkTitlesPreferShortTitles = false;
$wgLinkTitlesMinimumTitleLength = 3;
$wgLinkTitlesParseHeadings = false;
$wgLinkTitlesParseOnEdit = true;
$wgLinkTitlesParseOnRender = false;
$wgLinkTitlesSkipTemplates = false;
$wgLinkTitlesBlackList = array();
$wgLinkTitlesFirstOnly = false;
$wgLinkTitlesWordStartOnly = true;
$wgLinkTitlesWordEndOnly = true;
$wgLinkTitlesSmartMode = true;
$wgLinkTitlesNamespaceWhitelist = array();
$wgExtensionCredits['parserhook'][] = array(
'path' => FILE,
'name' => 'LinkTitles_5000',
'author' => '[https://www.mediawiki.org/wiki/User:Bovender Daniel Kraus]',
'url' => 'https://www.mediawiki.org/wiki/Extension:LinkTitles',
'version' => '2.2.0',
'descriptionmsg' => 'linktitles-desc'
);
$wgExtensionMessagesFiles['LinkTitles_5000'] = dirname( FILE ) . '/LinkTitles_5000.i18n.php';
$wgExtensionMessagesFiles['LinkTitlesMagic_5000'] = dirname( FILE ) . '/LinkTitles_5000.i18n.magic.php';
$wgAutoloadClasses['LinkTitles_5000'] = dirname( FILE ) . '/LinkTitles_5000.body.php';
$wgExtensionFunctions[] = 'LinkTitles_5000::setup';
// vim: ts=2:sw=2:noet
Forgot about this question from a long time ago, but it turns out MediaWiki has a buit in function for this
$myNamespace = $article->getTitle()->getNamespace();
Since the article object is by default passed to an extension hooked to an on_save process, this will get the namespace as a numeric value.

Better way to check for URL in PHP

Is there a better way or elegance to do this? I've been using this code to check the similar url in database base on the pattern provide.
$menu_selected = '';
$uri_array = explode('/','commodity/statement/flour/factory/');
$menus = array(
'commodity/search/flour/factory/index',
'commodity/statement/sugar/branch/index'
);
$pattern_parts = explode('/', '=/*/=/=/*');
foreach ($menus as $menu) {
$url_parts = explode('/',$menu);
if( count($pattern_parts) == count($url_parts) ){
#[i] Trim down for wildcard pattern
foreach($pattern_parts as $i => $part ){
if( $part == '*' ) {
unset($pattern_parts[$i]);
unset($url_parts[$i]);
unset($uri_array[$i]);
}
}
#[i] Join array and compare
if( join('/', $uri_array) == join('/', $url_parts) ) {
// Found and return the selected
$menu_selected = $menu;
break;
}
}
}

Categories