How to detect client country, locale in laravel 4 - php

I want to detect my client country or locale which they open website from or get the browser recommended language.
For Example, if you open the browser in Japan it will give me country code or country name current user opened like "en-jp" or "japan".
After Searching I found out that "Zend Framework" has function to detect the user/environmental in Zend_locale.
So I wonder if I can do the same in laravel 4 or if not what solution you suggest in any method (php, javascript, checking ip, etc.)?
Thank you in advanced.

Ok I know the answers of my questions as following:
How to detect the client country?
As far as I know we need to use geoIP service to detect the client IP which can tell where the client using from (e.g. maxmind)
But this is not solution to detect and alter my website language, if you looking for this solution in laravel 4 I will show you in next question
How to check the language that client want to use? (locale in laravel4)
In summarize I found some of ways that can get which language that client want to use by following:
HTTP Header (HTTP_ACCEPT_LANGUAGE) in $_SERVER['HTTP_ACCEPT_LANGUAGE'] equal to Request::server('HTTP_ACCEPT_LANGUAGE') in laravel4. Which these header tell us the language that current client browser want to use.
Direct request - In this condition we will get direct request from client which language they want to use. For easy example like we give them the
<select>
<option val="en">English</option>
<option val="th">Thailand</option>
</select>
And they select from it send to server via url Ex: www.Test.com/en
Cookies (optional) - We can get the cookies from browser which we provide the language that last use by current user. Which is we must send the cookies after they visited the site for first times.
Before I use it I store the support languages array in app/config/app.php by following:
'languages' => array('en','th','jp'),
All of it I modify the code in app/filter.php to get all above data and processing with my app by following:
App::before(function($request){
// 1. get the request langugage
$url_lang = Request::segment(1);
// 2. get Cookie langugage
$cookie_lang = Cookie::get('language');
// 3. Get the Browser Request language
$browser_lang = substr(Request::server('HTTP_ACCEPT_LANGUAGE'), 0, 2);
// 4. Start Checking the request language
// Check that Language tha request is support or not?
if(!empty($url_lang) AND in_array($url_lang, Config::get('app.languages')))
{
// Check whether the request url lang not same as remember in cookies
if($url_lang != $cookie_lang)
{
// Cookie::forever('language',$url_lang);
Session::put('language', $url_lang);
}
// Set the App Locale
App::setLocale($url_lang);
}
// Check that has Language in Forever Cookie and is it support or not?
else if(!empty($cookie_lang) AND in_array($cookie_lang, Config::get('app.languages')))
{
// Set App Locale
App::setLocale($cookie_lang);
}
// Check the browser request langugae is support in app?
else if(!empty($browser_lang) AND in_array($browser_lang, Config::get('app.languages')))
{
// Check whether the request url lang not same as remember in cookies
if($browser_lang != $cookie_lang)
{
// Cookie::forever('language',$browser_lang);
Session::put('language', $browser_lang);
}
// Set Browser Lang
App::setLocale($browser_lang);
}
else
{
// Default Application Setting Language
App::setLocale(Config::get('app.locale'));
}});
And after event of app is following:
App::after(function($request, $response){
$lang = Session::get('language');
if(!empty($lang))
{
// Send The language Cookies
$response->withCookie(Cookie::forever('language',$lang));
}
});
Hope this will help you out.

I use this Ip2Country for Laravel 4.2 that can retrieve a users country based on a given IP address. Creates a local database that utilizes the MaxMind GeoIP data, so no run time external API calls.
https://github.com/smalldogs/ip2country

I haven't tried this package, but you can probably use this:
https://github.com/webpatser/laravel-countries
If that doesn't get you all you need, you can probably combine it with the built in App::setLocale('en');
Referenced in:
http://cheats.jesse-obrien.ca

Speaks ohm89!
I used the following technique to capture the priority user linguam and show my site in your language:
1º - I created two new arrays in my app.php, alt_langs (supported by my site) and locale_prefix (language prefix to url):
'locale' => 'pt', // Default is en.
'alt_langs' => array ('pt', 'en', 'es'), // Supported by my site
'locale_prefix' => '', // Dinamic array.
2º - In routes.php file:
// Get the first segment url, ex.: mysite.com/pt and put this in locale_prefix array item:
if (in_array(Request::segment(1), Config::get('app.alt_langs'))) {
App::setLocale(Request::segment(1));
Config::set('app.locale_prefix', Request::segment(1));
}
// Here i usin the prexix to show right language site:
Route::group(array('prefix'=>Config::get('app.locale_prefix')), function()
{
Route::get('', array('uses' => 'HomeController#index'));
});
// And here i usin the http_accept_language to redirect him to default browser language:
Route::get('/', function(){
$lang = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2);
return Redirect::to($lang);
});
I hope I have helped.o/

Related

Analytics track custom events in new Web+App

I used to track custom events (API hits) with google analytics and PHP via cURL, but now analytics is deprecating this method. I understood that the new analytics Web+App is used to track this kind of events, but i cannot find anything that allows me to track those events.
my current code:
$response = $client->post('https://www.google-analytics.com/collect', [
'form_params' => [
'v' => 1,
't' => 'event',
'ec' => 'ap1-v1-xxx',
'ea' => 'invoke',
'el' => 'MY-API',
'tid' => 'XXXXXXXX',
'cid' => '555'
]
]);
Doing this, i was able to track every hit and have statistics about API usage, this is what the analytics panel looked-like:
But, as i said, analytics is deprecating this method, and it stopped tracking my hits:
https://support.google.com/firebase/answer/9167112?ref_topic=6386699
There is a way to keep track these custom events? I can't find anything alike in PHP or cURL whatsoever.
Thanks!
It's not so much the method (measurement protocol) has been deprecated, it's that it is using a new, as of yet apparently undocumented, version 2 of the measurement protocol.
That makes sense - you cannot sent hit type anymore (because there is now a single type event, whose name can be customized), and you cannot send event category, action and label, since those no longer exist, and have been replaced by event parameters.
Since there does not seem to be documentation yet, you can do a bit of reverse engineering. I looked at the request issued by the code from a web&app property (actually gtag.js) for a pageview:
https://www.google-analytics.com/g/collect? // endpoint, remains the same
v=2 // protocol version, v2
&tid=G-XXXXXXXXXX // tracking id
&_p=1253409603 // no idea, don't think this needs to be set
&sr=1920x1080 // screen resolution, not applicable to a serverside call
&ul=de-de // user agent language, probably not relevant for a serverside call
&cid=533127994.1575982871 // client id
&_s=1 // no idea
&en=pageview // event - this corresponds broadly to hit type t in the previous version
&dl=http://localhost/test2.html // document location
&dr= // document referrer, not relevant for a serverside call
&dt=Title // document title
&sid=1575982870 // no idea
&sct=1 // no idea
&seg=1 // no idea
I think for a serverside application you can ignore all parameters marked with "no idea" (I assume that is something determined by the Javascript tracking code).
Instead of "v=1" you need to set "v=2", and instead of "t" for hit type you need "en" for event name. I will see if I can work out how to sent event parameters (I am in the office and don't really have time to experiment), but in any case this should be enough to get you started (I tested a call via curl and it showed up in the realtime section of a web&app property, so it should work for you, too).

Restrict content elements with IP in TYPO3

My requirement is to restrict a content element with IP of a specific country (Eg: Austria). That means people visiting the website from Austrian IPs should be visible the content element and for all other users, it should be hidden. I am using geoip solution to check the country. I wrote a user function to implement this feature. I wrote a small extension and set hidden flag 1 and 0 based on countries. But due to TYPO3 caching, I want to clear the cache everytime to reflect the changes in frontend. I included the extension as USER_INT, and extension is non-cachable. But unfortunately not working. Functionality working, but due to caching changes not reflect in realtime.
$uid = 175; // uid of the content element needs to be hidden
$geoplugin = new \geoPlugin();
$geoplugin->locate();
$countryCode = $geoplugin->countryCode;
if( $countryCode == 'AT' ){
$GLOBALS['TYPO3_DB']->exec_UPDATEquery('tt_content', 'uid IN ('.$uid.')', array('hidden' => 0));
}else{
$GLOBALS['TYPO3_DB']->exec_UPDATEquery('tt_content', 'uid IN ('.$uid.')', array('hidden' => 1));
}
Is there any method available in TYPO3 to restrict content element for specific IP / Countries? or can you guys suggest a solution to fix this please?
The solution of Jost is much less dirty than hiding the element in the database depending on the visitors country. By your way the database probably changed on every user visit.
Just create a micro extension.

Soundcloud get track ID from link (PHP)

Okay, so I'm using php to post soundcloud widgets on my website(no need to explain why and how because thath's not wath's important)
Here is my code:
if (strpos($post['link'], 'soundcloud.com') !== FALSE)
{
echo "<iframe width=\"500\" height=\"150\" scrolling=\"no\" frameborder=\"no\"
src=\"https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/".$trackID."&color=ff6600&auto_play=false&show_artwork=true\"></iframe>";
}
My variable $post['link'] outputs the soundcloud link in this form https://soundcloud.com/alex-oancea/best-thing-about-you-original
What I would like to do is get the track's id from the link and declare it as $trackID because as you can see in my code(in the src="" part), the widget uses the track's ID
I have looked into the soundcloud API and many other threads on this site but I didin't find how to do this or how to write the code...
Thanks in advance!
Check http://developers.soundcloud.com/docs#resolving
You can click the PHP button on the example and get a good way of getting a track ID:
<?php
require_once 'Services/Soundcloud.php';
// create a client object with your app credentials
$client = new Services_Soundcloud('YOUR_CLIENT_ID');
// a permalink to a track
$track_url = 'http://soundcloud.com/forss/voca-nomen-tuum';
// resolve track URL into track resource
$track = json_decode($client->get('resolve', array('url' => $track_url)));
Now $track->id is your track ID.
Just be aware you need the SoundCloud API for this, and you'll probably have to register your app with SoundCloud to use the service. I have not had personal experience with any of this so I can't provide any information about those processes.
If you experiment on your local machine (xampp in your case), you CANNOT make it work, beause the 'REDIRECT_URL' cannot be anything else but a valid link to a hosted domain. The API just does not accept (for the good reason) url's containing "localhost" or or "192.168.x.x"-style url's. This is simply because the API really sends info to the 'REDIRECT_URL' and it needs to be able to reach it.
You need to get in touch with your hosting provider and setup a "live" dev environement.
Assuming you are using the php-soundcloud from the mptre's Github:
Check https://developers.soundcloud.com/docs#resolving (and even the '/resolve' indicated in the 'see also' section).
You can get a good way of getting a track ID by this way:
<?php
require_once 'Services/Soundcloud.php';
// create a client object with your app credentials
$client = new Services_Soundcloud('YOUR_CLIENT_ID', 'YOUR_CLIENT_SECRET');
// a permalink to a track
$track_url = 'http://soundcloud.com/forss/voca-nomen-tuum';
// resolve track URL into track resource
$track = json_decode($client->get('resolve', array('url' => $track_url), array(CURLOPT_FOLLOWLOCATION => true)));
// display all the information from that track resource
var_dump($track);
Now $track->id is your track ID.
?>
Just be aware you need the SoundCloud API for this, and you have to register your app with SoundCloud to use the service (Register your app).
Another information is that Webservers where a basedir restriction is set and/or safe mode is active don't allow the CURLOPT_FOLLOWLOCATION = true option. Here is a workaround for these webservers in the Soundcloud.php file.

How to change domain type and VNC listen address with libvirt-php?

I'm currently developing a snippet of code to create a libvirt KVM domain. Currently, the script is in working condition, but I'm unsatisfied with the way that I'm having to do things. As it stands, I'm having to load the domain XML using the PHP bindings, manually change it, then undefine and redefine the domain, all to change the domain type, and VNC address. I would like to know if there are any better alternatives to the way that I'm doing this below (The code that I'm not happy with is on lines 5 & 6). I feel like the PHP binding documentation is extremely lacking, which is why I haven't found a solution to this problem yet. I know that I should be able to do what I'm wanting to do because virt-manager can do it.
$vnc = "PGdyYXBoaWNzIHR5cGU9J3ZuYycgcG9ydD0nLTEnIGF1dG9wb3J0PSd5ZXMnIGxpc3Rlbj0nMC4wLjAuMCcgcGFzc3dkPSdfX1BBU1NfXyc+CiAgICAgIDxsaXN0ZW4gdHlwZT0nYWRkcmVzcycgYWRkcmVzcz0nMC4wLjAuMCcvPgogICAgPC9ncmFwaGljcz4="; // VNC config (base64)
$dom = libvirt_domain_lookup_by_name($c, $command['parameters']['name']); // Get domain resource
setBridge($dom, $command['parameters']['networks'][0]['mac']); // Replace network configuration with an interface bridge
setISO($dom, "/var/lib/libvirt/ISOs/Win7Pro.iso"); // Set the CD-ROM ISO
$xml = libvirt_domain_get_xml_desc($dom, null); // Get XML
domain_change_xml($c, $dom, str_ireplace("<domain type='qemu'>", "<domain type='kvm'>", str_ireplace("<graphics type='vnc' port='-1' autoport='yes'/>", str_ireplace("__PASS__", rand(10000000, 99999999), base64_decode($vnc)), $xml))); // Replace domain type and graphics block
libvirt_domain_create($dom); // Start the domain
function setBridge($dom, $mac) {
libvirt_domain_update_device($dom, "<interface type='bridge'><mac address=".escapeshellarg($mac)."/><source bridge='br0'/><model type='e1000'/></interface>", VIR_DOMAIN_DEVICE_MODIFY_CONFIG);
}
function setISO($dom, $iso) {
libvirt_domain_update_device($dom, "<disk type='file' device='cdrom'><driver name='qemu' type='raw'/><source file=".escapeshellarg($iso)."/><target dev='hdc' bus='ide'/><readonly/></disk>", VIR_DOMAIN_DEVICE_MODIFY_CONFIG);
}

Form keys (CSRF) in CakePHP

I have seen in some MVC applications the use of Token keys to prevent CSRF. A typical example of where it may be used is on the delete method for a post.
And I've seen implementations using both GET and POST methods.
An example GET request link with a token:
https://domain.com/posts/G7j/delete/EOwFwC4TIIydMVUHMXZZdkbUR0cluRSkFzecQy3m5pMTYVXRkcFIBWUZYLNUNSNgQKdnpTWu
And an example of a POST request with a token:
<form action="/posts/G7j/delete" method="post">
<input type="hidden" name="token" value="EOwFwC4TIIydMVUHMXZZdkbUR0cluRSkFzecQy3m5pMTYVXRkcFIBWUZYLNUNSNgQKdnpTWu" />
<button type="submit">Delete</button>
</form>
I've been looking into implementing this into my CakePHP applications based on the documents: http://book.cakephp.org/2.0/en/core-libraries/components/security-component.html
And according to the documents, adding the Security component auto adds the form key to all forms that use the Form Helper.
e.g.
public $components = array(
'Security' => array(
'csrfExpires' => '+1 hour'
)
);
However I have some questions:
1.) Why use POST over GET for some actions such as delete? As the request in the controller will check if the user is authenticated, has permission, and that it has the correct form key.
2.) How can I use the security component with a GET request in CakePHP? Presume I would also need to handle the routing as well.
Firstly CakePHP uses post links to delete as an added level of security because lets say for example your authentication system is not 100% secure and users can access a delete method by manually typing in a URL - if I go in and type /users/delete/10 , I can actually delete users on your server which is risky as you can imagine.
Secondarily GET requests can be cached or bookmarked so users who bookmark these links could end up navigating to broken links which is never a good thing ,also sensitive data will be visible in the URL so for example if someone bookmarks a login page with the GET variables intact - this could compromise there security.
Finally you can easily generate your own tokens using the following code :
$string = Security::hash('string', 'sha1 or md5', true);
print $this->Html->link("Link to somewhere",array("controller"=>"users","action"=>"delete",$string));
The above will use the salt key setup in your core config file but you can also replace true with a custom salt.
For the first question:
The reason probably lies in the definition of HTTP methods. GET is defined as one of the safe methods, which means that it can not be used for changing the state of the server but only for retrieving information. You can read more on the HTTP methods on this link. Since HTML forms are not capable of sending HTTP DELETE request the 'workaround' is to use some of the available methods and if you rule out the GET as a 'safe method' it leaves POST. You can of course use GET to delete stuff, many do, but GET request is by convention expected not to change anything.
edit: If you are interested to read more about HTTP methods and browser/HTML support check out this SO question
johhniedoe pointed me to Croogo 1.3 for an example of how they are have done something similar to what I asked in my question. Because 1.3 was targeted to CakePHP prior to 2.x, the code was a little out of date, so I've amended it as follows:
First create the link (in this case a delete link) with the CSRF Token used by the Security Component passed as a parameter called token.
<?php echo $this->Html->link('Delete', array('action'=>'delete','token'=>$this->params['_Token']['key'])); ?>
Next I've created a wildcard Route Connection to handle the token (this isn't essential usually, but because we're not using the NAMED Token and I wanted to keep the URL cleaner):
Router::connect('/:controller/:action/:token',
array('controller' => 'action'),
array(
'pass' => array('token')
)
);
And then finally handle it in your method like so:
public function delete(){
if (!isset($this->params['token']) || ($this->params['token'] != $this->params['_Token']['key'])) {
$this->Security->blackHoleCallback = '__blackhole';
} else {
// do delete
}
}
This basically says if the token doesn't match then use the blackhole callback function __blackhole, which I define in my AppController to show an error.
One last thing to be aware of though is that you must allow the token to be used more than once and last for example an hour, this is because otherwise the token will be reset and no longer match after the GET request is sent.
public $components = array(
'Security' => array(
'csrfExpires' => '+1 hour',
'csrfUseOnce' => false
)
);

Categories