I'm trying to detect the Safari browser using a method described in w3docs.
I've tried ,
<?php
ob_start();
session_start();
function getBrowser()
{
$user_agent = $_SERVER['HTTP_USER_AGENT'];
$browser = "N/A";
$browsers = [
'/msie/i' => 'Internet explorer',
'/firefox/i' => 'Firefox',
'/safari/i' => 'Safari',
'/chrome/i' => 'Chrome',
'/edge/i' => 'Edge',
'/opera/i' => 'Opera',
'/mobile/i' => 'Mobile browser',
];
foreach ($browsers as $regex => $value) {
if (preg_match($regex, $user_agent)) {
$browser = $value;
}
}
return $browser;
}
$agent = getBrowser();
echo $agent;
?>
it returns chrome for chrome, mobile browser for mobile browser , but not for safari. Is there no way to detect the Safari (Iphone) browser?
Anyone is welcome to share any knowledge/help regarding this.
You need to shortcut your loop, so that it exits as soon as it finds a matching value:
foreach ($browsers as $regex => $value) {
if (preg_match($regex, $user_agent)) {
return $value;
}
}
And then you might want a default if nothing is found:
foreach ($browsers as $regex => $value) {
if (preg_match($regex, $user_agent)) {
return $value;
}
}
return 'unknown';
Otherwise, you'll traverse the whole list every time, and (probably) always match the last one "mobile" because it's likely to also appear in the string.
Related
I need to check for the existence of a variable.
Variables are not necessarily created in order 1.2.3. They could be created 2.4.3.1. These are also not created at the same time on the same page. So I am just wanted to check for the existence of the variable.
$_SESSION['rule1']
$_SESSION['rule2']
$_SESSION['rule3']
$_SESSION['rule4']
<?
if(isset($_SESSION['rule'.*wildcard*'])) {
do something
}
?>
I'm not sure how to go about this. The answer probably lies in REGEX but I am horrible with REGEX.
If you don't know need to know which rule* key is in the session array, only if any of them are present, then you could try this:
<?php
function prefixExists(array $assoc_array, $prefix)
{
$length = strlen($prefix);
foreach ($assoc_array as $key => $unused)
{
if (strncmp($key, $prefix, $length) === 0) {
return true;
}
}
return false;
}
Testing as follows:
session_start();
var_dump(prefixExists($_SESSION, 'rule'));
$_SESSION['rule3'] = 'some value from form';
var_dump(prefixExists($_SESSION, 'rule'));
Gives output:
bool(false)
bool(true)
Here is another solution with the use of preg_match:
function arrayHasSimilarKey(array $array, $matchKey)
{
$pattern = '/' . str_replace('*', '.*', $matchKey) . '/i';
foreach ($array as $key => $value) { echo $key.PHP_EOL;
if (preg_match($pattern, $key)) {
return true;
}
}
return false;
}
$testArray = ['abc' => 1, 'test_1' => 1, 'test_2' => 1, 'test2_1' => 1, 'test3_2' => 1];
$tests = [
0 => arrayHasSimilarKey($testArray, 'test*'), // true
1 => arrayHasSimilarKey($testArray, 'test2*_2'), // false
2 => arrayHasSimilarKey($testArray, 'test3*'), // true
3 => arrayHasSimilarKey($testArray, 'test3*_1'), // false
4 => arrayHasSimilarKey($testArray, '*_2') // false
];
var_dump($tests);
In your case, $testArray would be $_SESSION
I need to validate an input from text area.
It is complex and i'm unable to figure out how i can do it best?
Can you guys help?
Input from the text area are basically host names or ips. The input can be of any of the following formats:
x.x.x.x (single IP)
x.x.x.x-x.x.x.x (range of IPs)
x.x.x.x/x.x.x.x (IP and mask)
x.x.x.x/xx (IP and CIDR)
URL (with or without http:// and https:// prefixes)
domain name in format: xxxxxxx.xxx
Also multiple values can be given, like:
192.168.1.1
192.168.1.2/192.168.1.4
I am able to get the lines of textbox using the following code:
$text = trim($targets);
$textAr = explode("\n", $text);
$textAr = array_filter($textAr, 'trim');
foreach ($textAr as $line) {
}
I am unable to proceed further. Please help.
Thanks,
Dave
If you don't mind being slightly loose on your validation, you can do something simple such as this:
function filter_fn($input)
{
$input = trim($input);
$regex_ip = '/^([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})$/';
$regex_range = '/^([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})-([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})$/';
$regex_cidr = '/^([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\/[0-9]{1,2})$/';
$regex_sub = '/^([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\/[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})$/';
if (filter_var($input, FILTER_VALIDATE_REGEXP, array('options' => array('regexp' => $regex_ip)))) {
return $input;
}
if (preg_match($regex_range, $input)) {
return $input;
}
if (preg_match($regex_cidr, $input)) {
return $input;
}
if (preg_match($regex_sub, $input)) {
return $input;
}
if (filter_var($input, FILTER_VALIDATE_URL)) {
return $input;
}
if (filter_var('http://'.$input, FILTER_VALIDATE_URL)) {
return $input;
}
return false;
}
$textAr = explode("\n", $text);
$textAr = array_filter($textAr, 'trim');
foreach ($textAr as $line) {
$success = filter_var($line, FILTER_CALLBACK, array('options' => 'filter_fn'));
if (!$success) {
// It failed.
} else {
// It worked.
}
}
Note that in my example, I used both preg_match and filter_var with FILTER_VALIDATE_REGEXP. Both are identical in this case, so that first filter_var could have just as easily been replaced with:
preg_match($regex_ip, $input)
Or, even:
filter_var($input, FILTER_VALIDATE_IP)
For example
I use
$content = nl2br($_POST['content']);
and when I type in something like this in my form
"I'll be going to the office today"
It'll return
"I\'ll be going to the office today"
Is there a way I can remove the \'s? or am I using the nl2br function wrong?
nl2br() does no such thing! You have magic quotes on. Turn them off.
I'm guessing you're getting information via a POST or GET; try something like this:
<?php
if (get_magic_quotes_gpc()) {
$process = array(&$_GET, &$_POST, &$_COOKIE, &$_REQUEST);
while (list($key, $val) = each($process)) {
foreach ($val as $k => $v) {
unset($process[$key][$k]);
if (is_array($v)) {
$process[$key][stripslashes($k)] = $v;
$process[] = &$process[$key][stripslashes($k)];
} else {
$process[$key][stripslashes($k)] = stripslashes($v);
}
}
}
unset($process);
}
?>
More information on the PHP manual
Try to use stripslashes( $content ).
I am trying to make an unofficial API for server Strava.cz using PHP's function file_get_contents(); but it doesn't work. What's wrong?
function strava_czLogin($machine,$user,$pass){
//Sends the request
$src = file_get_contents(
'http://m.strava.cz/Stravnik/formprihlaseni.aspx',
false,
stream_context_create(
array('http'=>array('header' => "User-Agent:(none; StravaCekujNET; Linux x86_64; rv:1.0)\r\n"))
)
);
$src = mb_convert_encoding($src,'utf-8','auto'); //Encoding correction
//Works with the cookies (yummy!)
$cookies = array();
foreach ($http_response_header as $value) {
if (preg_match('/^Set-Cookie:\s*([^;]+)/', $value, $matches)) {
parse_str($matches[1], $tmp);
$cookies += $tmp;
}
}
$sessionId = "";
foreach ($cookies as $key => $value) {
if ($key == "ASP_NET_SessionId"){$sessionId = $value;}
}
//Checks the result and returns the sessionId
if (preg_match('<form name="aspnetForm" method="post" action="stravnik.aspx" id="aspnetForm">',$src)){
return array(true,$sessionId);
}else{
return array(false,null);
}
}
function strava_czCheck($sessionId){
//Sends request
$src = file_get_contents('http://m.strava.cz/Stravnik/objednavky.aspx',false,stream_context_create(array('http'=>array('header' => "User-Agent:(none; StravaCekujNET; Linux x86_64; rv:1.0)\r\nCookie: ASP_NETSession=".$sessionId."\r\n"))));
$src = mb_convert_encoding($src,'utf-8','auto'); //Zajistí správné kódování
echo $src; //Prints the response - "Application Error"
//Some irrelevant code here
//Returns the result
if ($arr==null) {return array(false,null);}
else {return array(true,$arr);}
}
The server returns "Application Error" like when you're logged out.
And don't ask me why I'm doing this - I'm the man who asks
If you want to deal with cookies, use curl. Maybe this will help:
https://rupeshpatel.wordpress.com/2012/05/12/general-purpose-function-for-curl/
I've created a router in PHP which takes a DSL (based on the Rails 3 route) and converts it to Regex. It has optional segments (denoted by (nested) parenthesis). The following is the current lexing algorithm:
private function tokenize($pattern)
{
$rules = array(
self::OPEN_PAREN_TYPE => '/^(\()/',
self::CLOSE_PAREN_TYPE => '/^(\))/',
self::VARIABLE_TYPE => '/^:([a-z0-9_]+)/',
self::TEXT_TYPE => '/^([^:()]+)/',
);
$cursor = 0;
$tokens = array();
$buffer = $pattern;
$buflen = strlen($buffer);
while ($cursor < $buflen)
{
$chunk = substr($buffer, $cursor);
$matched = false;
foreach ($rules as $type => $rule)
{
if (preg_match($rule, $chunk, $matches))
{
$tokens[] = array(
'type' => $type,
'value' => $matches[1],
);
$matched = true;
$cursor += strlen($matches[0]);
}
}
if (!$matched)
{
throw new \Exception(sprintf('Problem parsing route "%s" at char "%d".', $pattern, $cursor));
}
}
return $tokens;
}
Are there any obvious speed-ups that I am missing? Any way to abandon preg_* altogether, or combine the regexes into one pattern, etc?
Here is the xhprof callgraph (benchmark uses ~2500 unique routes for testing):
I know the best solution would be not to call this for every request (I plan on caching with APC, etc), but would like to make it as efficient as possible for people that use this library without APC enabled.
EDIT:
I also wrote a quick state machine version, which seems to perform better. I'm still open to suggestions on either front, as I believe the first code was more elegant.
private function tokenize2($pattern)
{
$buffer = '';
$invariable = false;
$tokens = array();
foreach (str_split($pattern) as $char)
{
switch ($char)
{
case '(':
if ($buffer)
{
$tokens[] = array(
'type' => $invariable ? self::VARIABLE_TYPE : self::TEXT_TYPE,
'value' => $buffer,
);
$buffer = '';
$invariable = false;
}
$tokens[] = array(
'type' => self::OPEN_PAREN_TYPE,
);
break;
case ')':
if ($buffer)
{
$tokens[] = array(
'type' => $invariable ? self::VARIABLE_TYPE : self::TEXT_TYPE,
'value' => $buffer,
);
$buffer = '';
$invariable = false;
}
$tokens[] = array(
'type' => self::CLOSE_PAREN_TYPE,
);
break;
case ':':
if ($buffer)
{
$tokens[] = array(
'type' => $invariable ? self::VARIABLE_TYPE : self::TEXT_TYPE,
'value' => $buffer,
);
$buffer = '';
$invariable = false;
}
$invariable = true;
break;
default:
if ($invariable && !(ctype_alnum($char) || '_' == $char ))
{
$invariable = false;
$tokens[] = array(
'type' => self::VARIABLE_TYPE,
'value' => $buffer,
);
$buffer = '';
$invariable = false;
}
$buffer .= $char;
break;
}
}
if ($buffer)
{
$tokens[] = array(
'type' => $invariable ? self::VARIABLE_TYPE : self::TEXT_TYPE,
'value' => $buffer,
);
$buffer = '';
}
return $tokens;
I ended up just using the state machine for performance reasons, and caching the entire lexing process with APC (because... why not).
If anyone has anything to contribute, I'll happily move the answer.
Interesting code :).
I'm not quite sure what you're saying with "caching the entire lexing process with APC", so I may be suggesting what you're already doing.
Can you just cache the input URL, and the result above the actual lexing process? You don't look to be applying any permissions based restrictions here, so the cache is global. Routes tend to be limited in number, even on a large site, with a few very hot spots. Bypass the lexing entirely and hit the cache on any previously used route.