I need to display site visitor's continent. I am using geoip functionality to pull 2 letter code, which I can get to work very easily. However, just displaying 'AS' for Asia to the site visitor is clearly undesirable. So I'm trying to convert that. This is what I am trying to do. . .
<?php
$continent = geoip_continent_code_by_name($_SERVER['REMOTE_ADDR']);
$africa = array('AF');
$antarctica = array('AN');
$asia = array('AS');
$europe = array('EU');
$northamerica = array('NA');
$oceania = array('OC');
$southamerica = array('SA');
if ($africa) {
echo 'Africa';
}
elseif ($antarctica) {
echo 'Antarctica';
}
elseif ($asia) {
echo 'Asia';
}
elseif ($europe) {
echo 'Europe';
}
elseif ($northamerica) {
echo 'North America';
}
elseif ($oceania) {
echo 'Australia and Oceania';
}
elseif ($southamerica) {
echo 'South America';
}
else {
echo '';
}
?>
It just displays 'Africa' no matter where the site visitor, so it's getting stuck there. I'm reading though PHP tutorials but can't figure out what I'm doing wrong. My if, else and elsifs look good as far as I can tell.
Well, you're kind of going about it wrong.
You're getting the code correctly with your first line, but then you are creating a bunch of different arrays, each containing one of the possible codes. Then you are checking for the existence of each array, and since you just created them, they do exist, so your IF block will stop with the first check and output Africa.
What you want to do is create one array that contains all the codes as keys, with the output name as values, and then just use the code you got from $_SERVER to return the matching value from that array. (I got the list of codes from the manual)
$continent = geoip_continent_code_by_name($_SERVER['REMOTE_ADDR']);
$continents = [
'AF' => 'Africa',
'AN' => 'Antarctica',
'AS' => 'Asia',
'EU' => 'Europe',
'NA' => 'North America',
'OC' => 'Oceania',
'SA' => 'South America',
];
echo $continents[$continent];
It's worth a little explanation for WHY your IF block functions the way it does. PHP is loosely typed, meaning that you don't have to explicitly set the type of variables. So when PHP encounters a variable it has to guess about how to use it. So when you say if($africa), php tries to make sense of $africa in the context of a boolean question, and since it DOES exist and is not 0 or false, it sees it as TRUE and executes the first block.
Related
I have a random content script that has worked perfectly but now seems to have a glitch.
It's the "Spotlight On:" story on the upper lefthand corner at http://fiction.deslea.com/index2.php and the code is as follows:
$storyspotlights = array("bluevial", "biophilia", "real", "edgeofreality",
"limitsofperception", "markofcain", "spokenfor", "closer",
"feildelm", "purgatory", "elemental");
$randomstoryID = array_rand($storyspotlights);
$randomstory = $storyspotlights[$randomstoryID];
switch ($randomstory) {
case ($randomstory == 'closer'):
$storyspotlightheader = "<div class='storyspotlightheader'>Closer</div>";
$storyspotlighttext = "snip";
//some stories snipped
case ($randomstory == 'bluevial'):
$storyspotlightheader = "<div class='storyspotlightheader'>The Blue
Vial</div>";
$storyspotlighttext = "snip";
break;
//more stories snipped
}
print($storyspotlightheader);
print($storyspotlighttext);
My problem is - all the stories from Blue Vial to Spoken For appear when you refresh the page, in random order (although Blue Vial seems to stick a fair bit). These were the stories in the script originally.
Since then I have added the last four to the array and the content generation switch case fragment, but these last four stories never, ever appear in the randomiser. I've literally sat and refreshed for hours. I've confirmed over and over that the updated script is on the server, and even deleted and re-uploaded it.
I did try unset and also $storyspotlights = array() at the beginning of the script at various stages of troubleshooting, but to no avail. I also tried moving the new stories to the start of the array - no change there either.
What am I missing?
It's surprising this works at all. That's not how you use switch..case.
switch (<value to compare>) {
case <value to compare against>:
...
}
That means you write this:
switch ($randomstory) {
case 'closer':
...
}
With what you've written it's actually executing like:
if ($randomstory == ($randomstory == 'closer')) ...
Also make sure you have not actually forgotten some break statements, which would make the code fall through to the next case and indeed make certain cases "more sticky" than others.
Also, I'd simplify the whole thing to this:
$stories = array(
array('header' => '...', 'text' => '...'),
array('header' => '...', 'text' => '...'),
...
);
$story = $stories[array_rand($stories)];
echo $story['header'];
echo $story['text'];
I'm not sure what's wrong with this script. When I run it it only gives me the first letter of the abbreviation.
I didn't write the abbreviation part, I found that online. The only parts of the script that are mine are the GET and Includes.
I've set the state variable to a state and I still get the same thing so I know it's not my portion of the code. If anyone knows what the issue is please let me know.
Here is the updated code as suggested. Still having the same problem.
$state = 'Alabama';
function convert_state($name, $get = 'abbr') {
$states = array(
'Alabama'=>'AL',
'Alaska'=>'AK',
'Arizona'=>'AZ',
'Arkansas'=>'AR',
'California'=>'CA',
'Colorado'=>'CO',
'Connecticut'=>'CT',
'Delaware'=>'DE',
'Florida'=>'FL',
'Georgia'=>'GA',
'Hawaii'=>'HI',
'Idaho'=>'ID',
'Illinois'=>'IL',
'Indiana'=>'IN',
'Iowa'=>'IA',
'Kansas'=>'KS',
'Kentucky'=>'KY',
'Louisiana'=>'LA',
'Maine'=>'ME',
'Maryland'=>'MD',
'Massachusetts'=>'MA',
'Michigan'=>'MI',
'Minnesota'=>'MN',
'Mississippi'=>'MS',
'Missouri'=>'MO',
'Montana'=>'MT',
'Nebraska'=>'NE',
'Nevada'=>'NV',
'New Hampshire'=>'NH',
'New Jersey'=>'NJ',
'New Mexico'=>'NM',
'New York'=>'NY',
'North Carolina'=>'NC',
'North Dakota'=>'ND',
'Ohio'=>'OH',
'Oklahoma'=>'OK',
'Oregon'=>'OR',
'Pennsylvania'=>'PA',
'Rhode Island'=>'RI',
'South Carolina'=>'SC',
'South Dakota'=>'SD',
'Tennessee'=>'TN',
'Texas'=>'TX',
'Utah'=>'UT',
'Vermont'=>'VT',
'Virginia'=>'VA',
'Washington'=>'WA',
'West Virginia'=>'WV',
'Wisconsin'=>'WI',
'Wyoming'=>'WY'
);
if($get == 'name') {
// in this case $name is actually the abbreviation of the state name and you want the full name
$states = array_flip($states);
}
return $states[$name];
}
There's an excellent answer to this question already, but since the OP is still having problems with this, here's an alternate solution. Please note that the array $a2s needs to be fully populated, as I only added two states to keep this short. Save the following to the file of your choice (eg: state.php):
<?php
$state = $_GET['state'];
echo convert_state($state);
function convert_state($key) {
$a2s = array(
'AL'=>'Alabama',
'CA'=>'California'
);
$array = (strlen($key) == 2 ? $a2s : array_flip($a2s));
return $array[$key];
}
?>
To run the above, you'd type one of the following in your browser (assuming your file is state.php):
state.php?state=AL
state.php?state=Alabama
The code is designed to work either way.
You should refactor your $states as:
$states = array(
'Alabama' => 'AL',
'Alaska' => 'AK',
[...]
);
Then your function becomes:
function convert_state($name, $get = 'abbr') {
$states = [.. see above ..];
if($get == 'name') {
// in this case $name is actually the abbreviation of the state name and you want the full name
$states = array_flip($states);
}
return $states[$name];
}
I am creating a 3D Secure PHP Project. I am having a rather bizzare issue in that the "MD" code is going missing when re-submitting the Array of data
My code is as follows :
$paRes = $_REQUEST['PaRes'];
$md = $_REQUEST['MD'];
require "payment_method_3d.php";
x_load('cart','crypt','order','payment','tests');
/*
* For Debugging Purposes
* Only.
echo "The Value Of PaRes is : ";
echo $paRes;
*/
$soapClient = new SoapClient("https://www.secpay.com/java-bin/services/SECCardService?wsdl");
$params = array (
'mid' => '',
'vpn_pswd' => '',
'trans_id' => 'TRAN0095', // Transaction ID MUST match what was sent in payment_cc_new file
'md' => $md,
'paRes' => $paRes,
'options' => ''
);
It seems that the $_REQUEST['MD'] string seems to go missing AFTER the soap call. Although I am having difficulty print this out to the screen. The strange thing is the $paRes variable works without issue.
Any ideas why this would be the case?
Check your case. PHP array keys are case sensitive. From this little bit of code it looks as if the request variable may be 'md' instead of 'MD'.
Try $md = $_REQUEST['md'];
PHP array statements are case sensitive, so this should work:....
$md = $_REQUEST['md'];
Thanks for your responses guys.
What was happening was the include page was sitting in front of the request methods and causing issues loading the REQUEST methods to the page.
I am working on project where I need to implement SphinxSearch with Cake php. So I am simply trying to use a component and behaviour into it. The link to it, is :-
http://bakery.cakephp.org/articles/eugenioclrc/2010/07/10/sphinx-component-and-behavior
I am requesting Sphinx API like below :
$sphinx = array('matchMode' => SPH_MATCH_ALL, 'sortMode' => array(SPH_SORT_EXTENDED => '#relevance DESC'));
$results = $this->ModelName->find('all', array('search' => 'Search_Query', 'sphinx' => $sphinx));
pr($result);
For above it is working fine ,but when I tried to minimise the response time querying to a particular field of the table (using extended match modes,i.e. SPH_MATCH_EXTENDED2) , Sphinx just fails to output any result. The extended query which I used is given below :-
$sphinx = array('matchMode' => SPH_MATCH_EXTENDED2, 'sortMode' => array(SPH_SORT_EXTENDED => '#relevance DESC'));
$results = $this->ModelName->find('all', array('search' => '#Field_name Search_Query', 'sphinx' => $sphinx));
pr($results);
Can anyone recognise where am I going wrong with it? Please help if I am going wrong some where.
Thanks in advance.
Btw, when you use EXTENDED2 mode make sure your rank mode is set accordingly.
Edit:
Anyway back to you problem, looking at that component/behavior code you can see right away that no error checking is done whatsoever. Try changing the code a bit so you can at least see the errors and/or warnings.
Component
if(!isset($query['search'])){
$result = self::$sphinx->Query('', $indexes);
} else {
$result = self::$sphinx->Query($query['search'], $indexes);
}
if ($result === false) {
// throw new SphinxException();
die(self::$sphinx->GetLastError());
}
$warn = self::$sphinx->GetLastWarning();
if ($warn) echo $warn;
Behavior
$result=$this->runtime[$model->alias]['sphinx']->search($s);
if ($result === false) {
die($this->runtime[$model->alias]['sphinx']->GetLastError());
}
$warn = $this->runtime[$model->alias]['sphinx']->GetLastWarning();
if ($warn) echo $warn;
I hope that helps.
As you said ,
Sphinx just fails to output any result.
That means it's an error :
Please check whether you have added the specific field to the indexing by using sql_query
Also check if the field you are searching for is not an attribute
As per the sphinx documentation :
Attributes, unlike the fields, are not full-text indexed. They are stored in the index, but it is not possible to search them as full-text, and attempting to do so results in an error.
I'm trying to build multilangual site.
I use this piece of code to detect users language. If you havent chosen a language, it will include your language file based on HTTP_ACCEPT_LANGUAGE.
I don't know where it gets it from though:
session_start();
if (!isset($_SESSION['lang'])) {
$_SESSION['lang'] = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2);
}
elseif (isset($_GET['setLang']) && $_GET['setLang'] == 'en') $_SESSION['lang'] = "en";
elseif (isset($_GET['setLang']) && $_GET['setLang'] == 'sv') $_SESSION['lang'] = "sv";
elseif (isset($_GET['setLang']) && $_GET['setLang'] == 'pl') $_SESSION['lang'] = "pl";
elseif (isset($_GET['setLang']) && $_GET['setLang'] == 'fr') $_SESSION['lang'] = "fr";
include('languages/'.$_SESSION['lang'].'.php');
It works for me and includes the polish lang file. But is this code accurate? Or is there another way?
The browser generally sends a HTTP header, name Accept-Language, that indicates which languages the user is willing to get.
For instance, this header can be :
Accept-Language: en-us,en;q=0.5
There is notion of priority in it, btw ;-)
In PHP, you can get this in the $_SERVER super global :
var_dump($_SERVER['HTTP_ACCEPT_LANGUAGE']);
will get me :
string 'en-us,en;q=0.5' (length=14)
Now, you have to parse that ;-)
If I edit my preferences in the browser's option to say "I want french, and if you can't serve me french, get me english from the US ; and if you can't get me that either, just get me english), the header will be :
Accept-Language: fr-fr,en-us;q=0.7,en;q=0.3
And, from PHP :
string 'fr-fr,en-us;q=0.7,en;q=0.3' (length=26)
For more informations, you can take a look at [section 14.4 of the HTTP RFC][1].
And you probably can find lots of code example in PHP to parse that header ; for instance : Parse Accept-Language to detect a user's language
Have fun !
Here's the script I used for a bi-lingual site. It is to be used as index.php of mysite.com. Based on the user's browser's language preference, it would redirect to desired language version of the site or the default language site if the site in user's preferred langauge was not available.
<?php
// List of available localized versions as 'lang code' => 'url' map
$sites = array(
"en" => "http://en.mysite.com/",
"bn" => "http://bn.mysite.com/",
);
// Get 2 char lang code
$lang = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2);
// Set default language if a `$lang` version of site is not available
if (!in_array($lang, array_keys($sites)))
$lang = 'en';
// Finally redirect to desired location
header('Location: ' . $sites[$lang]);
?>
I know there already many good solutions, but have found my own way to solve this problem.
<?php
$prefLocales = array_reduce(
explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']),
function ($res, $el) {
list($l, $q) = array_merge(explode(';q=', $el), [1]);
$res[$l] = (float) $q;
return $res;
}, []);
arsort($prefLocales);
/*
This get you from headers like this
string 'en-US,en;q=0.8,uk;q=0.6,ru;q=0.4' (length=32)
array like this
array (size=4)
'en-US' => float 1
'en' => float 0.8
'uk' => float 0.6
'ru' => float 0.4
*/
Code will convert HTTP_ACCEPT_LANGUAGE string to array with locales as keys and weight as values, sorted from high value to low. So you can just get one by one with array_shift to get the best match with your site locales.
You can use: Locale::acceptFromHttp().
Tries to find locale that can satisfy the language list that is requested by the HTTP "Accept-Language" header.
Your code looks just fine. You might want to add a final else default choice if the visitor asks for a language you aren't providing.
Also, if the visitor himself selects a language you should save that choice in a persistent cookie and check its value, giving it precedence over HTTP_ACCEPT_LANGUAGE.
As far as I can tell Youtube does use HTTP_ACCEPT_LANGUAGE, but at the same time uses IP geolocation to suggest a change in language if the langauge of the visitor's country doesn't match that. Definitely annoying.
Just nitpicking: if you're gonna add languages to the list a switch() statement might be more readable.
Here's a function for selecting the best out of a group of supported languages. It extracts languages from Accept-Language, then sorts the given array of languages according to their priority.
function select_best_language($languages) {
if (!$_SERVER['HTTP_ACCEPT_LANGUAGE']) return $languages[0];
$default_q=100;
foreach (explode(",",$_SERVER['HTTP_ACCEPT_LANGUAGE']) as $lqpair) {
$lq=explode(";q=",$lqpair);
if ($lq[1]) $lq[1]=floatval($lq[1]); else $lq[1]=$default_q--;
$larr[$lq[0]]=$lq[1];
}
usort($languages,function($a,$b) use ($larr) { return $larr[$b]<=>$larr[$a]; });
return $languages[0];
}
$lang = select_best_language(['en','fr','it']);
Try This
function getUserLanguage() {
$langs = array();
if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
// break up string into pieces (languages and q factors)
preg_match_all(
'/([a-z]{1,8}(-[a-z]{1,8})?)\s*(;\s*q\s*=\s*(1|0\.[0-9]+))?/i',
$_SERVER['HTTP_ACCEPT_LANGUAGE'],
$lang_parse
);
if (count($lang_parse[1])) {
// create a list like 'en' => 0.8
$langs = array_combine($lang_parse[1], $lang_parse[4]);
// set default to 1 for any without q factor
foreach ($langs as $lang => $val) {
if ($val === '') {
$langs[$lang] = 1;
}
}
// sort list based on value
arsort($langs, SORT_NUMERIC);
}
}
//extract most important (first)
reset($langs);
$lang = key($langs);
//if complex language simplify it
if (stristr($lang, '-')) {
list($lang) = explode('-', $lang);
}
return $lang;
}
This is also possible. It will use english as default if .php is not available.
$lang = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2);
(#include_once 'languages/'.$lang.'.php') or (#include_once 'languages/en.php');
I solved this issue for PHP7.4+ with the code below. It strips out the first two letters of the locale code, takes into account cases like 'en-US' and produces a map like:
$map = [
'en' => 1,
'de' => 0.8,
'uk' => 0.3
];
The code is as follows:
$header = 'en-US,de-DE;q=0.8,uk;q=0.3';
$pattern = '((?P<code>[a-z-_A-Z]{2,5})([;q=]+?(?P<prio>0.\d+))?)';
preg_match_all($pattern, $header, $matches);
['code' => $codes, 'prio' => $values] = $matches;
$map = \array_combine(
\array_map(fn(string $language) => strtolower(substr($language, 0, 2)), \array_values($codes)),
\array_map(fn(string $value) => empty($value) ? 1 : (float)$value, \array_values($values))
);
Please note that the regex is probably suboptimal, improvement suggestions are welcome.
Named capture groups are always in the order of matching, so we can use array_combine safely.
if(isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])){
$parts=explode(';',$_SERVER['HTTP_ACCEPT_LANGUAGE']);
$langs=explode(',',$parts[0]);
var_dump($langs);
}