I am using Laravel Framwork for my php software and I ran into an issue with localizaing the text within the JaveScript files.
I have a database value that sets the locale of each user.
App::setLocale(Auth::user()->lang) in the Middleware folder. It works as expected on the different blades using either #lang('file.name') or trans('file.name').
For my JavaScript files I am using this method. It works fine, but it seems that it doesn't update the locale based on the value in the middleware, but based on the locale value in config/app.php.
The php pages all work and update according the the database value.
Any idea what I might be missing?
Problem in the link that you provided is that it will get all the translations for current language and it will cache that forever. So even though you are changing languages, /js/lang.js will always return same cached response.
While it is good idea to cache the response of reading all translation files for language, when you create the cache you need to do that per language and to use unique cache key per language (look at the code)
// Localization
Route::get('/js/lang.js', function () {
$minutes = 10;
$lang = App::getLocale();
// each language it will be cached with different key
// example: "en.lang.js", "fr.lang.js", ...
$strings = Cache::remember($lang.'.lang.js', $minutes, function() use ($lang) {
$files = glob(resource_path('lang/' . $lang . '/*.php'));
$strings = [];
foreach ($files as $file) {
$name = basename($file, '.php');
$strings[$name] = require $file;
}
return $strings;
});
return response('window.i18n = ' . json_encode($strings) . ';')
->header('Content-Type', 'text/javascript');
})->name('assets.lang');
Related
Recently I have been doing a lot of work in PHP and I have become familiar with how it works. I stand by what I have said before; That every problem has an endless amount of solutions. So that is what I am after, solutions that solve the same problem.
In this case, I want variables/references to values from localstorage:
localStorage.setItem("user", "bananaflakes55");
localStorage.getItem("user");
and directly include them in PHP files. Now I have found out that using echo have a variety of uses, for example:
echo '<script type="text/javascript"> window.location.replace("' . $refclinklogin . '"); </script>';
Granted that the value there are on serverside -> client side. In this case I want similar solutions that necessarily wont require me to create a GET or POST, with HTML elements like forms, that connect these.
To sum up, I want solutions that can bring values from local and session storage, to PHP. Bring forth some funky ideas, if possible. From what I have read it is a tricky one.
Even if i understand what you want, process sould be running from PHP to client rather than the reverse.
With this in mind, a light solution can be something like that :
window.addEventListener("load", function() {
let request = new XMLHttpRequest();
request.open("POST", 'localStorageToSession.php', true);
request.onload = function () {
let saveResponse = request.responseText;
// if you want a callback or use some script return
}
let data = "jsonLocalStorage=" + JSON.stringify(window.localStorage);
request.send(data);
}) ;
Once the page is loaded, send all localStorage parsed in json to a PHP treatment (here called localStorageToSession.php).
So you can convert localstorage as $_SESSION. Something like that :
$_SESSION['jsLocalStorage'] = json_decode($_POST['jsonLocalStorage'], true) ;
Then you can use $_SESSION['jsLocalStorage'] in your backend treatments. Don't forget to add session_start() on all your files.
You can save the xml request in a function and call once localStorage is updated).
Even if that solution works, i don't recommand it if you have to deal with safety informations like passwords or user special access.
I am using Google Autocomplete (under Maps Javascript API) in Angular 5.
For the purpose of my website, I retrieve details of a place, which includes any available photos. For the photos, I will get the photo URL via the getURL() method.
============
What works previously
Previously, I am able to save the url in the database and use that same url to retrieve the photos at a later date. Example of the URLs includes:
https://lh3.googleusercontent.com/p/AF1QipM3QnVu-6W-ZtoTry29MOzDt7vpWzPZAPZbBfqZ=w600-h500-k
https://lh3.googleusercontent.com/p/AF1QipPQ5imb4nzfK1TxG7KAFx2vEx1SoYXeQApA6SVX=w600-h500-k
https://lh4.googleusercontent.com/-l_W16EbIqzk/WS5E5R9_VbI/AAAAAAAAnD8/ajWr1IeY7solMudnxIV21vjqmxLt8CJOACLIB/w300-h250-k
============
Situation now
However, in recent weeks, the same getURL() method returns photos that expire. I have no problem seeing the photo when I first retrieved it. As usual, I save the url to my database. However, after a few days, I am unable to retrieve the same images. Example includes:
https://maps.googleapis.com/maps/api/place/js/PhotoService.GetPhoto?1sCmRaAAAAiEX-USwjAvitgPnxuaW7stCrTkQMxyydpcmlg5IrEWnSUS5D3Z2D9evQ_n41Ght-8dr3cZtjvx4oINIEpqj4Z4fvaCyqv6xF0oPC_lw88P6FUQ7SXP2vElr61Zi568IdEhBWY_7xGFNHvdQyDqxZApR3GhS-IM17Pp8oMGlMK0FrXW310tsPCw&3u2000&4u1000&5m1&2e1&key=AIzaSyAbdivx4G0igYO5yr3vTUJcQF5s8lTdXho&callback=none&token=96678
https://maps.googleapis.com/maps/api/place/js/PhotoService.GetPhoto?1sCmRaAAAAkz5xG6DVQSbwHyBIQIshs2FedNARq6oG0Ea6gUxvljPdnHFJqcJniD0gkd2BZQ7-IPc6FPVlYYb7G0t8K_-8hVYizZl4HGy5V1QiE4sjdWLhyWX7MnJYEA61zoup_fbpEhDWYpcVACyQ6RKsqpyS-bQKGhQw8Tg2O8rcGJfaKI0jW3T7XKAYZg&3u2000&4u1000&5m1&2e1&key=AIzaSyAbdivx4G0igYO5yr3vTUJcQF5s8lTdXho&callback=none&token=20957
https://maps.googleapis.com/maps/api/place/js/PhotoService.GetPhoto?1sCmRaAAAAfLQZlWahAqUSlQA5y7-NTeYLMDim6M1L_ht3_qNCSL4dBeX2VWVdhzuJXeqGcKN30XAv3WZHtY2QUXaoKV5fVGSUld2IdOKfV0bv32kEFUdgMlqou9Ij5YVaJ15mfoVcEhB-6hiiaiPS3349mCZMYOPyGhTrEZUg0XGOuBW1rsrLlpmaO9nvqg&3u2000&4u1000&5m1&2e1&key=AIzaSyAbdivx4G0igYO5yr3vTUJcQF5s8lTdXho&callback=none&token=38662
============
What may be the problem
From the makeup of the URLs, there are obvious differences. The older URLs comes with the googleusercontent as the domain name. While the newer photos end with a token. Right now, I am still able to retrieve the older photos even though i may have added them months ago. For the new photos, it expires after a few days.
I understand that there are solutions that require the use of photo_reference, however, I am unable to find a way to retrieve photo_reference via the javascript API I am using. I have tried to use Places Service method (new google.maps.places.PlacesService) but it returns the same getURL() method which retrieves the same temporary URL as above.
=======================
Thus my question are:
Does anyone know whether the change in url is intended or it may be an error from google? If it is intended, is there any way to get a permanent url that does not expire.
Does anyone know how to retrieve photo_reference via the google javascript API?
Many thanks for your help in advance.
Google says this is intentional behavior and that the only thing users should be “caching” is the “place_id”.
See: https://issuetracker.google.com/issues/110711934
unfortunately, I think to retrieve the photo reference, a separate Place Details request will need to be made using the Place ID.
I worked around this by writing a serverside function to recursively follow the redirect path and get the ultimate photo url. Example in elixir:
def follow(url) when is_binary(url) do
case HTTPoison.get(url) do
{:ok, %HTTPoison.Response{status_code: status_code, headers: headers}} when status_code > 300 and status_code < 400 ->
case get_location_header(headers) do
[url] when is_binary(url) ->
follow(url)
_ ->
{:error, :no_location_header}
end
{:ok, %HTTPoison.Response{status_code: 200}} ->
{:ok, url}
reason ->
{:error, reason}
end
end
defp get_location_header(headers) do
for {key, value} <- headers, String.downcase(key) == "location" do
value
end
end
so now i can take the long
https://maps.googleapis.com/maps/api/place/js/PhotoService.GetPhoto?1sCm... url and run it through follow() which returns the googleusercontent url for the image itself.
i then pass THAT url to filestack to copy and store and serve over CDN...
bit of a crazy workaround, but it finally fixed this issue for us.
Here is a code in which you can pass the temporary URL fetched from Google places service API get photos, and it returns a permanent URL that you store in your database for later use.
<?php
function get_redirect_url($url){
$redirect_url = null;
$url_parts = #parse_url($url);
if (!$url_parts) return false;
if (!isset($url_parts['host'])) return false; //can't process relative URLs
if (!isset($url_parts['path'])) $url_parts['path'] = '/';
$sock = fsockopen($url_parts['host'], (isset($url_parts['port']) ? (int)$url_parts['port'] : 80), $errno, $errstr, 30);
if (!$sock) return false;
$request = "HEAD " . $url_parts['path'] . (isset($url_parts['query']) ? '?'.$url_parts['query'] : '') . " HTTP/1.1\r\n";
$request .= 'Host: ' . $url_parts['host'] . "\r\n";
$request .= "Connection: Close\r\n\r\n";
fwrite($sock, $request);
$response = '';
while(!feof($sock)) $response .= fread($sock, 8192);
fclose($sock);
if (preg_match('/^Location: (.+?)$/m', $response, $matches)){
if ( substr($matches[1], 0, 1) == "/" )
return $url_parts['scheme'] . "://" . $url_parts['host'] . trim($matches[1]);
else
return trim($matches[1]);
} else {
return false;
}
}
function get_all_redirects($url){
$redirects = array();
while ($newurl = get_redirect_url($url)){
if (in_array($newurl, $redirects)){
break;
}
$redirects[] = $newurl;
$url = $newurl;
}
return $redirects;
}
function get_final_url($url){
$redirects = get_all_redirects($url);
if (count($redirects)>0){
return array_pop($redirects);
} else {
return $url;
}
}
echo get_final_url($temporary_google_url);
?>
Source: http://w-shadow.com/blog/2008/07/05/how-to-get-redirect-url-in-php/
I am developing a project, for which I want to scrape the contents of a website in the background and get some limited content from that scraped website. For example, in my page I have "userid" and "password" fields, by using those I will access my mail and scrape my inbox contents and display it in my page.
I done the above by using javascript alone. But when I click the sign in button the URL of my page (http://localhost/web/Login.html) is changed to the URL (http://mail.in.com/mails/inbox.php?nomail=....) which I am scraped. But I scrap the details without changing my url.
Definitely go with PHP Simple HTML DOM Parser. It's fast, easy and super flexible. It basically sticks an entire HTML page in an object then you can access any element from that object.
Like the example of the official site, to get all links on the main Google page:
// Create DOM from URL or file
$html = file_get_html('http://www.google.com/');
// Find all images
foreach($html->find('img') as $element)
echo $element->src . '<br>';
// Find all links
foreach($html->find('a') as $element)
echo $element->href . '<br>';
The HTTP Request
First, you make an HTTP request to get the content of the page. There are several ways to do that.
fopen
The most basic way to send an HTTP request, is to use fopen. A main advantage is that you can set how many characters are read at a time, which can be useful when reading very large files. It's not the easiest thing to do correctly, though, and it's not recommended to do this unless you're reading very large files and fear running into memory issues.
$fp = fopen("http://www.4wtech.com/csp/web/Employee/Login.csp", "rb");
if (FALSE === $fp) {
exit("Failed to open stream to URL");
}
$result = '';
while (!feof($fp)) {
$result .= fread($fp, 8192);
}
fclose($fp);
echo $result;
file_get_contents
The easiest way, is just using file_get_contents. If does more or less the same as fopen, but you have less options to choose from. A main advantage here is that it requires but one line of code.
$result = file_get_contents('http://www.4wtech.com/csp/web/Employee/Login.csp');
echo $result;
sockets
If you need more control of what headers are sent to the server, you can use sockets, in combination with fopen.
$fp = fsockopen("www.4wtech.com/csp/web/Employee/Login.csp", 80, $errno, $errstr, 30);
if (!$fp) {
$result = "$errstr ($errno)<br />\n";
} else {
$result = '';
$out = "GET / HTTP/1.1\r\n";
$out .= "Host: www.4wtech.com/csp/web/Employee/Login.csp\r\n";
$out .= "Connection: Close\r\n\r\n";
fwrite($fp, $out);
while (!feof($fp)) {
$result .= fgets($fp, 128);
}
fclose($fp);
}
echo $result;
streams
Alternatively, you can also use streams. Streams are similar to sockets and can be used in combination with both fopen and file_get_contents.
$opts = array(
'http'=>array(
'method'=>"GET",
'header'=>"Accept-language: en\r\n" .
"Cookie: foo=bar\r\n"
)
);
$context = stream_context_create($opts);
$result = file_get_contents('http://www.4wtech.com/csp/web/Employee/Login.csp', false, $context);
echo result;
cURL
If your server supports cURL (it usually does), it is recommended to use cURL. A key advantage of using cURL, is that it relies on a popular C library commonly used in other programming languages. It also provides a convenient way for creating request headers, and auto-parses response headers, with a simple interface in case of errors.
$defaults = array(
CURLOPT_URL, "http://www.4wtech.com/csp/web/Employee/Login.csp"
CURLOPT_HEADER=> 0
);
$ch = curl_init();
curl_setopt_array($ch, ($options + $defaults));
if( ! $result = curl_exec($ch)) {
trigger_error(curl_error($ch));
}
curl_close($ch);
echo $result;
Libraries
Alternatively, you can use one of many PHP libraries. I wouldn't recommend using a library, though, as it's likely to be overkill. In most cases, you're better off writing your own HTTP class using cURL under the hood.
The HTML parsing
PHP has a convenient way to load any HTML into a DOMDocument.
$pagecontent = file_get_contents('http://www.4wtech.com/csp/web/Employee/Login.csp');
$doc = new DOMDocument();
$doc->loadHTML($pagecontent);
echo $doc->saveHTML();
Unfortunately, PHP support for HTML5 is limited. If you run into errors trying to parse your page content, consider using a third party library. For that, I can recommend Masterminds/html5-php. Parsing an HTML file with this library is very similar to parsing an HTML file with DOMDocument.
use Masterminds\HTML5;
$pagecontent = file_get_contents('http://www.4wtech.com/csp/web/Employee/Login.csp');
$html5 = new HTML5();
$dom = $html5->loadHTML($html);
echo $html5->saveHTML($dom);
Alternatively, you can use eg. my library PHPPowertools/DOM-Query. It uses customized version of Masterminds/html5-php under the hood parsing an HTML5 string into a DomDocument and symfony/DomCrawler for conversion of CSS selectors to XPath selectors. It always uses the same DomDocument, even when passing one object to another, to ensure decent performance.
namespace PowerTools;
// Get file content
$pagecontent = file_get_contents( 'http://www.4wtech.com/csp/web/Employee/Login.csp' );
// Define your DOMCrawler based on file string
$H = new DOM_Query( $pagecontent );
// Define your DOMCrawler based on an existing DOM_Query instance
$H = new DOM_Query( $H->select('body') );
// Passing a string (CSS selector)
$s = $H->select( 'div.foo' );
// Passing an element object (DOM Element)
$s = $H->select( $documentBody );
// Passing a DOM Query object
$s = $H->select( $H->select('p + p') );
// Select the body tag
$body = $H->select('body');
// Combine different classes as one selector to get all site blocks
$siteblocks = $body->select('.site-header, .masthead, .site-body, .site-footer');
// Nest your methods just like you would with jQuery
$siteblocks->select('button')->add('span')->addClass('icon icon-printer');
// Use a lambda function to set the text of all site blocks
$siteblocks->text(function( $i, $val) {
return $i . " - " . $val->attr('class');
});
// Append the following HTML to all site blocks
$siteblocks->append('<div class="site-center"></div>');
// Use a descendant selector to select the site's footer
$sitefooter = $body->select('.site-footer > .site-center');
// Set some attributes for the site's footer
$sitefooter->attr(array('id' => 'aweeesome', 'data-val' => 'see'));
// Use a lambda function to set the attributes of all site blocks
$siteblocks->attr('data-val', function( $i, $val) {
return $i . " - " . $val->attr('class') . " - photo by Kelly Clark";
});
// Select the parent of the site's footer
$sitefooterparent = $sitefooter->parent();
// Remove the class of all i-tags within the site's footer's parent
$sitefooterparent->select('i')->removeAttr('class');
// Wrap the site's footer within two nex selectors
$sitefooter->wrap('<section><div class="footer-wrapper"></div></section>');
You can use the cURL extension of PHP to do HTTP requests to another web site from within your PHP page script. See the documentation here.
Of course the downside here is that your site will respond slowly because you will have to scrape the external web site before you can present the full page/output to your user.
Have you tried OutWit Hub? It's a whole scraping environment. You can let it try to guess the structure or develop your own scrapers. I really suggest you have a look at it. It made my life much simpler.
ZR
I just realized that I cannot call directly on a URL from my AngularJS application due to CORS. Therefore, I expect I will have to use the Javascript API.
The following link provides me with the data I want:
https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=' + myPosition.lat + ',' + myPosition.lng + '&rankby=distance&key=' + key + '&sensor=false&type=clothing_store
However, I cannot figure how to achieve the same using the Javascript API. I found this in the documentation, but I do not need a map - just the names and coordinates of the nearby stores.
How can I get a hold of the same data using the Javascript API?
If you've already got a Google Maps for JS API Map Key, you can do a Places query from the server side. Note, however, that you're limited to 1000 queries per day.
You can probably do this directly in your client and avoid CORS issues, but here's how I've done it previously using PHP:
<?php
function ReturnEmpty()
{
// Something's wrong, return an empty set.
echo '{"d":[]}';
}
$q = (isset($_GET["query"])) ? $_GET["query"] : 'NULL';
if( $q == "" )
{
ReturnEmpty();
}
else
{
// I'm showing the "textsearch" option, but there is also a "nearbysearch" option..
$url = "https://maps.googleapis.com/maps/api/place/textsearch/json?query="
. urlencode($q)
. "&key=YOUR_GOOGLE_MAPS_KEY_HERE";
$json = file_get_contents($url);
$data = json_decode($json, true);
echo $data;
}
?>
You can use the nearbySearch(request, callback) method on google.maps.places.PlacesService(map).
In your case, the request should have a location (that contains the lat and lng) and a radius.
There are code samples here.
I am not sure if this is the best way to do it, but I have a button that when pressed it call a onClick JS function and it passed two parameters. I want to save those two parameters on a php session, then load another page and use those values.
So, I know that if I use something like this on PAGE !:
<?php
session_start();
$message1 = "A message";
$message2 = "Another message";
$_SESSION['routineName'] = $message1;
$_SESSION['dayName'] = $message2;
?>
I can go to PAGE 2, and by using $_SESSION['routineName'] I can use that info.
So, on PAGE 1 I have that code inside the function that is called with my onClick:
function trackIt(routine, dayName)
{
<?php
session_start();
$message1 = "A message";
$message2 = "Another message";
$_SESSION['routineName'] = $message1;
$_SESSION['dayName'] = $message2;
?>
}
I tried things like:
function trackIt(routine, dayName)
{
<?php
session_start();
$_SESSION['routineName'] = ?> routine; <?php
$_SESSION['dayName'] = $message2;
?>
}
and others, but nothing works.
And this is how I am calling the onClick (trackIt) function:
echo('<td colspan="3" style="background-color:#005673; text-align:right; padding: 4px 0px;">
<button class="btnTrack" onClick="trackIt(\'' . $name . '\' , \'' . $nameday1 . '\')" >Track It!</button></td>');
What I want to do is to save both, routine and dayName, into the session.
Is it possible to save JS variables/parameters into PHP Session?
PS: I am using Wordpress.
Thanks!
The PHP code you put in your files is not executed at Javascript run time, it is executed even before the page gets sent to the client. So you can't access $_SESSION from anywhere within your content, you need to do that from Wordpress's code. Usually this is done via a plugin.
You need to pass your Javascript variables to a server side PHP. As #Grasshopper said, the best (or at least most maintainable way) is through AJAX:
// This is your JAVASCRIPT trackit function
function trackIt(routine, day) {
$.post(
'/wp-setvar.php',
{
routine : routine,
day : day
}, // You can add as many variables as you want (well, within reason)
function success(data) {
// Here we should receive, given the code below, an object
// such that data.result is a string saying "OK".
// Just in case you need to get back something from the server PHP.
// Otherwise just leave this function out.
}
);
};
On the server, you need to create a specific file to accept the incoming variables (it would be best if you did this from a plugin, in order not to add files outside the installation: such practices are frowned upon by security scanners such as WordFence). This here below is a butcher's solution.
<?php /** This is wp-setvar.php */
/** Set up WordPress environment, just in case */
require_once( dirname( __FILE__ ) . '/wp-load.php' );
session_id() || session_start();
nocache_headers();
// DO NOT, FOR ANY REASON, ACCESS DIRECTLY $_SESSION
// ONLY USE A VARIABLE WITHIN $_SESSION (here, "ajjx")
// OTHERWISE THIS MAY ALLOW ANYONE TO TAKE CONTROL OF YOUR INSTALLATION.
$_SESSION['ajjx'] = $_POST;
Header('Content-Type: application/json;charset=utf8');
die(json_encode(array(
'result' => 'OK', // This in case you want to return something to the caller
)));
Now whenever you need the session-saved variable, e.g. "routine", you put
<?php
...
$value = '';
if (array_key_exists('ajjx', $_SESSION)) {
if (array_key_exists('routine', $_SESSION['ajjx']) {
$value = $_SESSION['ajjx']['routine'];
}
}
Or you can define a function in your plugin,
function ajjx($varname, $default = '') {
if (array_key_exists('ajjx', $_SESSION)) {
if (array_key_exists($varname, $_SESSION['ajjx']) {
return $_SESSION['ajjx'][$varname];
}
}
return $default;
}
Then you just:
<?php print ajjx('routine', 'none!'); ?><!-- will print routine, or "none!" -->
or
<?php print ajjx('routine'); ?><!-- will print nothing if routine isn't defined -->
An even more butcherful solution is to add the function definition above within wp-config.php itself. Then it will be available everywhere in Wordpress. Provided you have access to wp-config.php. Also, backup wp-config first and use a full FTP client to do it; do not use a Wordpress plugin to edit it, since if wp-config crashes, the plugin may crash too... and you'll find yourself in a my-can-opener-is-locked-within-a-can situation.
If you don't feel comfortable with some of the above, it's best if you do nothing. Or practice first on an expendable Wordpress installation that you can reinstall easily.