I am trying to implement the HTML5 Server-sent events inside Laravel 4, I found this repo
the script uses server.php file to get it working. My question is how would I implement it to get it working with a Controller instead of a plain php file? So in the Javascript side it will look like this:
var source = EventSource('/notifications');
I tried this just to see if I get a response:
class NotificationsController extends BaseController {
public function index()
{
$response = Response::view('notifications.index');
$response->header('Content-Type', 'text/event-stream');
$response->header('Cache-Control', 'no-cache');
return $response;
}
}
and in the view:
<?php
echo "id: 4" . PHP_EOL;
echo "data: this is a message" . PHP_EOL;
flush();
Finally I get this error in google-chrome network panel:
caution: provisional headers are shown
Found it, the solution was quite simple:
the JavaScript in the main Layout:
var source = new EventSource('/notifications');
source.onmessage = function(e) {
console.log(e);
}
in the NotificationsController#index:
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
if (true)
{
echo "data: <p> Hello There </p>\n";
}
flush();
I got back the MessageEvent !
Related
I'm trying to implement server sent events in a Laravel project.
I created an endpoint in the backend that looks like this:
public function stream(Request $request)
{
$response = new StreamedResponse(function () use ($request) {
$i = 0;
while (true) {
$i++;
echo 'data: ' . $i . "\n\n";
ob_flush();
flush();
if (connection_aborted()) {
break;
}
usleep(20000);
}
});
$response->headers->set('Content-Type', 'text/event-stream');
$response->headers->set('X-Accel-Buffering', 'no');
$response->headers->set('Cache-Control', 'no-cache');
return $response;
}
The frontend part:
<script>
console.log("script started");
const eventSource = new EventSource('/stream');
eventSource.onmessage = function(event) {
console.log(event);
}
</script>
When I run the project with the builtin Laravel webserver the event stream seems to be working correctly and it looks like this in the console of the browser:
The problem is that all the other requests to my backend are blocked. So I tried using nginx and apache webserver. But unfortunately I'm running into a different problem then. The connection does not establish (readyState 0) and approximately every 5 seconds a new request to the /stream endpoint is generated:
I tried updating the nginx configuration as described here:
Nginx configuration
and I used other implementations of sse:
sse in laravel
I'm running out of ideas why this is not working. For this project websockets and polling are not an alternative. Hopefully someone of you has an idea and can help me with this.
I created a script that extracts photos in the gallery of a certain profile…
Using instagram-web-api
Unfortunately now it no longer works, instagram does not return the image of the media
This is the mistake:
ERR_BLOCKED_BY_RESPONSE
Instagram has changed it’s CORS policy recently? How I can fix?
for php; I changed my img src to this and it works like charm! Assume that $image is the instagram image cdn link came from instagram page:
'data:image/jpg;base64,'.base64_encode(file_get_contents($image))
EDIT FOR BETTER SOLUTION
I have also noticed that, this method is causing so much latency. So I have changed my approach and now using a proxy php file (also mentioned on somewhere on stackoverflow but I don't remember where it is)
This is my common proxy file content:
<?php
function ends_with( $haystack, $needle ) {
return substr($haystack, -strlen($needle))===$needle;
}
if (!in_array(ini_get('allow_url_fopen'), [1, 'on', 'true'])) {
die('PHP configuration change is required for image proxy: allow_url_fopen setting must be enabled!');
}
$url = isset($_GET['url']) ? $_GET['url'] : null;
if (!$url || substr($url, 0, 4) != 'http') {
die('Please, provide correct URL');
}
$parsed = parse_url($url);
if ((!ends_with($parsed['host'], 'cdninstagram.com') && !ends_with($parsed['host'], 'fbcdn.net')) || !ends_with($parsed['path'], 'jpg')) {
die('Please, provide correct URL');
}
// instagram only has jpeg images for now..
header("Content-type: image/jpeg");
readfile( $url );
?>
Then I have just converted all my instagram image links to this (also don't forget to use urlencode function on image links):
./proxyFile.php?url=https://www.....
It worked like charm and there is no latency anymore.
now 100% working.
You can try this.
corsDown
Using the Google translation vulnerability, it can display any image URL, with or without permission. All these processes are done by the visitor's IP and computer.
I have the same problem, when I try to load a Instagram's pictures url (I tried with 3 IP addresses), I see this on the console:
Failed to load resource: net::ERR_BLOCKED_BY_RESPONSE
You can see it here, the Instagram image doesn't load (Actually, when I paste this url on google it works, but Instagram puts a timestamp on there pictures so, it's possible it won't work for you).
It's very recent, 3 days ago, it works with no issues.
<img src="https://scontent-cdt1-1.cdninstagram.com/v/t51.2885-19/s320x320/176283370_363930668352575_6367243109377325650_n.jpg?tp=1&_nc_ht=scontent-cdt1-1.cdninstagram.com&_nc_ohc=nC7FG1NNChYAX8wSL7_&edm=ABfd0MgBAAAA&ccb=7-4&oh=696d56547f87894c64f26613c9e44369&oe=60AF5A34&_nc_sid=7bff83">
The answer is as follows. You can use the imgproxy.php file. You can do it like this:
echo '<a href="' . $item->link . '" class="image" target="_blank">
<span style="background-image:url(imgproxy.php?url=' . urlencode($thumbnail) . ');"> </span>
</a>';
Using PHP
u can grab content of the image and show it in php file as an image by setting the header:
<?php
$img_ctn = file_get_contents("https://scontent-ber1-1.cdninstagram.com/v/......");
header('Content-type: image/png');
echo $img_ctn;
You can display the Image using Base64 encoded.
Base64 func based on #abubakar-ahmad answer.
JavaScript:
export const checkUserNameAndImage = (userName) => {
/* CALL THE API */
return new Promise((resolve, reject) => {
fetch(`/instagram`, {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify({ userName }),
})
.then(function (response) {
return response.text();
})
/* GET RES */
.then(function (data) {
const dataObject = JSON.parse(data);
/* CALL BASE64 FUCNTION */
toDataUrl(dataObject.pic, function (myBase64) {
/* INSERT TO THE OBEJECT BASE64 PROPERTY */
dataObject.picBase64 = myBase64;
/* RETURN THE OBJECT */
resolve(dataObject);
});
})
.catch(function (err) {
reject(err);
});
});
};
Base64 func:
function toDataUrl(url, callback) {
var xhr = new XMLHttpRequest();
xhr.onload = function () {
var reader = new FileReader();
reader.onloadend = function () {
callback(reader.result);
};
reader.readAsDataURL(xhr.response);
};
xhr.open("GET", url);
xhr.responseType = "blob";
xhr.send();
}
Now, instead of using the original URL, use the picBase64 property:
<image src={data.picBase64)}/>
I have built a simple PHP based media proxy to minimize copy&paste.
https://github.com/skmachine/instagram-php-scraper#media-proxy-solving-cors-issue-neterr_blocked_by_response
Create mediaproxy.php file in web server public folder and pass instagram image urls to it.
<?php
use InstagramScraper\MediaProxy;
// use allowedReferersRegex to restrict other websites hotlinking images from your website
$proxy = new MediaProxy(['allowedReferersRegex' => "/(yourwebsite\.com|anotherallowedwebsite\.com)$/"]);
$proxy->handle($_GET, $_SERVER);
I was too lazy to do the suggested solutions and since i had a nodejs server sending me urls i just wrote new functions to get the images, convered them to base64 and sent them to my frontend. Yes it's slower and heavier but it gets the job done for me since i don't have a huge need for performance.
Fetch and return base64 from url snippet
const getBase64Image = async (url) => {
return new Promise((resolve, reject) => {
// Safety net so the entire up
// doesn't fucking crash
if (!url) {
resolve(null);
}
https
.get(url, (resp) => {
resp.setEncoding("base64");
body = "data:" + resp.headers["content-type"] + ";base64,";
resp.on("data", (data) => {
body += data;
});
resp.on("end", () => {
resolve(body);
});
})
.on("error", (e) => {
reject(e.message);
});
});
};
You don't need any external modules for this.
I want to obtain users' phone numbers via Google sign-in on my website. In JavaScript for the "sign in with Google" button, I'm including scope 'https://www.googleapis.com/auth/user.phonenumbers.read' for permission to read the user's phone number. Maybe instead of this scope, I need to use 'https://www.googleapis.com/auth/contacts.readonly'. In any case, how do I obtain a signed-in user's phone number in PHP or JavaScript? When a user clicks on the sign-in button then because of the scope Google does ask permission to share a phone number. In Google API Console -> Edit app registration -> Scopes, I've included this phone number scope. Also, I've enabled People API in the Google project. I've installed
composer require google/apiclient
From the front end i'm receiving id-token for the signed-in user. My PHP is:
<?php
require_once 'vendor/autoload.php';
$id_token = $_POST['idtoken'];
$client = new Google_Client(['client_id' => '349001386451-bpovja3t7soabdu3cbhnig12fqlr20o0.apps.googleusercontent.com']);
$payload = $client->verifyIdToken($id_token);
if ($payload) {
$userid = $payload['sub'];
echo "Userid: $userid";
} else {
echo "Invalid ID token";
}
( The above code has been edited from https://developers.google.com/identity/sign-in/web/backend-auth )
I'm a newbie to this. I've got my client-id, client-secret and user's id-token. I'm able to show the userid in the above code, how to display the phone number?
Edit: I downloaded my client_secret.json and tried another method:
index.php
<?php
require_once __DIR__.'/vendor/autoload.php';
session_start();
$client = new Google\Client();
$client->setAuthConfig('client_secret.json');
$client->setScopes(array('https://www.googleapis.com/auth/user.phonenumbers.read', 'https://www.googleapis.com/auth/contacts.readonly', 'profile'));
if (isset($_SESSION['access_token']) && $_SESSION['access_token']) {
$client->setAccessToken($_SESSION['access_token']);
$service = new Google_Service_PeopleService( $client );
$optParams = ['personFields' => 'phoneNumbers'];
$profile = $service->people->get( 'people/me', $optParams );
var_export($profile);
var_export( $profile->getPhoneNumbers() );
} else {
$redirect_uri = 'https://' . $_SERVER['HTTP_HOST'] . '/testing/oauth2callback.php';
header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}
--
oauth2callback.php
<?php
require_once __DIR__.'/vendor/autoload.php';
session_start();
$client = new Google\Client();
$client->setAuthConfigFile('client_secret.json');
$client->setRedirectUri('https://' . $_SERVER['HTTP_HOST'] . '/testing/oauth2callback.php');
$client->addScope(Google_Service_PeopleService::USER_PHONENUMBERS_READ);
if (! isset($_GET['code'])) {
$auth_url = $client->createAuthUrl();
header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));
} else {
$client->authenticate($_GET['code']);
$_SESSION['access_token'] = $client->getAccessToken();
$redirect_uri = 'https://' . $_SERVER['HTTP_HOST'] . '/testing/';
header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}
But when I'm running index.php it's giving error:
"error": { "code": 403, "message": "The caller does not have
permission to request "people/me". Request requires one of the
following scopes: [profile]."
But I do have included the profile scope in index.php
The phone number used for password reset will not be possible access:
It has been determined that we will not return the account recovery
phone number. The account recovery phone number is only intended for
specific usage like recovery the account when locked out. In the
interest of protecting user privacy this will not be returned in the
3rd party API.
I'm successfully getting phone number using a new 3rd method as given here:
https://developers.google.com/people/api/rest/v1/people/get?apix=true&apix_params=%7B%22resourceName%22%3A%22people%2Fme%22%2C%22personFields%22%3A%22phoneNumbers%22%7D
I copied the JavaScript code given in this link, removed all scopes except one, replaced YOUR_API_KEY and YOUR_CLIENT_ID, ran it on my server, in Firefox and it worked!
<script src="https://apis.google.com/js/api.js"></script>
<script>
/**
* Sample JavaScript code for people.people.get
* See instructions for running APIs Explorer code samples locally:
* https://developers.google.com/explorer-help/guides/code_samples#javascript
*/
function authenticate() {
return gapi.auth2.getAuthInstance()
.signIn({scope: "https://www.googleapis.com/auth/user.phonenumbers.read"})
.then(function() { console.log("Sign-in successful"); },
function(err) { console.error("Error signing in", err); });
}
function loadClient() {
gapi.client.setApiKey("YOUR_API_KEY");
return gapi.client.load("https://people.googleapis.com/$discovery/rest?version=v1")
.then(function() { console.log("GAPI client loaded for API"); },
function(err) { console.error("Error loading GAPI client for API", err); });
}
// Make sure the client is loaded and sign-in is complete before calling this method.
function execute() {
return gapi.client.people.people.get({
"resourceName": "people/me",
"personFields": "phoneNumbers"
})
.then(function(response) {
// Handle the results here (response.result has the parsed body).
console.log("Response", response);
},
function(err) { console.error("Execute error", err); });
}
gapi.load("client:auth2", function() {
gapi.auth2.init({client_id: "YOUR_CLIENT_ID"});
});
</script>
<button onclick="authenticate().then(loadClient)">authorize and load</button>
<button onclick="execute()">execute</button>
But it only reads the phone number(s) added in Google account's "About me": https://myaccount.google.com/profile
And not the phone number of Google account which is used for password reset. I actually want this number but don't know whether possible.
I'm trying to create telegram bot on Laravel with php-telegram-bot. I have installed webhook and now I get a message:
{"ok": true,
"result": {
"url": "https://.../api/telegram/hook/",
"has_custom_certificate": true,
"pending_update_count": 15,
"last_error_date": 1549043620,
"last_error_message": "Wrong response from the webhook: 301 Moved Permanently",
"max_connections": 40
}
}
What does it mean? I know what is 301 error mean, but can't understand what steps needed to solve this problem.
My controller:
public function hook()
{
$commands_paths = [
app_path() . '/Services/Telegram/Bots/Bitbd_BOT/Commands',
];
try {
// Create Telegram API object
$telegram = new Telegram($this->bot_api_key, $this->bot_username);
TelegramLog::initErrorLog(storage_path() . "/{$this->bot_username}_error.log");
TelegramLog::initDebugLog(storage_path() . "/{$this->bot_username}_debug.log");
TelegramLog::initUpdateLog(storage_path() . "/{$this->bot_username}_update.log");
// Add commands paths containing your custom commands
$telegram->addCommandsPaths($commands_paths);
$telegram->enableLimiter();
// Handle telegram webhook request
$handle = $telegram->handle();
} catch (TelegramException $e) {
echo $e->getMessage();
}
}
API routes:
Route::group(['prefix' => 'telegram'], function () {
Route::get('hook/set', 'TelegramController#setWebhook');
Route::any('hook','TelegramController#hook');
});
Some interesting: /api/telegram/hook correctly works only with ANY or GET option, POST method return empty page with vue, and i don't know why.
You probably have a problem in your webhook url, please check it again, And make sure that is correct and exists in your server.
Even https://example.com/folder/ is different with https://example.com/folder and you have to use / at the end of the address (In my case, I gave that error because of /).
Create a middleware in app/Http/Middleware/PreflightResponse.php
And paste this code:
<?php
namespace App\Http\Middleware;
use Closure;
class PreflightResponse
{
public function handle($request, Closure $next )
{
if ($request->getMethod() === "OPTIONS") {
return response('');
}
return $next($request);
}
}
Then in app/Http/Kernel.php, add in the global variable $middleware:
protected $middleware = [
Middleware\PreflightResponse::class,
];
This is a general solution, but you can specify as a named middleware and using in your routes.
That happens because of CORS and its security measures.
I hope that could help :D
I'm working on creating an AJAX powered RSS Feed. It is a single pane similar to Google Reader with a list of feeds on the left and the feed content on the right. When you click on any of the feeds this will trigger an ajax command (jquery's $.ajax()) that will trigger the RSSFeed class's public getFeed($feed_url) function (which in turn utilizes SimplePie to get the data needed.
This uses:
jQuery 1.9.1 to handle the AJAX calls and updating the browser
Twitter Bootstrap 2.3.0 for layout / normalization / styling
SimplePie 1.3.1 to handle the RSS feeds themselves.
When the page loads, I am using the getFeed($feed_url); to correctly get the data (this works):
<div class="row">
<div class="span7" id="feedBody">
<?php
$RSSFeed->getFeed("http://rss1.smashingmagazine.com/feed/");
?>
</div>
</div>
This works as expected. Then a feed item may be clicked and that would trigger the following AJAX command (alerts are there for debugging purposes):
"use strict";
//Update the feed
$("a.feedName").click(function(e) {
e.preventDefault();
var feedURL;
feedURL = $(this).attr("href");
$.ajax('model/RSSFeed.php', {
data: {url: feedURL},
beforeSend: function() {
$("#feedBody").html("<div class=\"alert alert-info span7\"><button type=\"button\" class=\"close\" data-dismiss=\"alert\">×</button><strong>Loading Feed…</strong>");
},
cache: false,
success: function(result) {
$("#feedBody").html(result);
alert(result);
},
error: function(result) {
$("#feedBody").hide();
alert("Error!");
}
});
});
Then model/RSSFeed.php sees this request and should use the following to trigger getting the new content:
if (isset($_GET['url'])) {
$RSS = new RSSFeed();
$RSS->getFeed($_GET['url']);
} else if(isset($_POST['url'])) {
$RSS = new RSSFeed();
$RSS->getFeed($_POST['url']);
}
This calls my RSSFeed class which is as follows:
class RSSFeed {
//Get the feed at the $feed_url and echo it out to the browser for the ajax request to display
public function getFeed($feed_url) {
$feed = new SimplePie($feed_url);
$feed->init();
$feed->handle_content_type();
foreach ($feed->get_items() as $item) {
$output = "<article>"
. "<h3>" . $item->get_title() . "</h3><p>";
if ($category = $item->get_category()) {
$output .= $category->get_label() . " ";
}
$output .= $item->get_date();
$output .= "</p><p>";
$output .= shorten($item->get_description(), 600) . "<br /><br />" . "Read More";
$output .= "</p>";
echo $output;
}//end foreach($feed->get_items() as $item)
}//end getFeed($feed_url)
//Begin setting up to allow Google Reader takeout files to be imported into the database.
public function importRSSFeeds($xmlFile, $DB) {
$xml = simplexml_load_file($xmlFile);
foreach($xml as $feed) {
foreach($feed->outline as $thisFeed) {
if($thisFeed->outline['type'] == "rss") {
$DB->addFeedToDatabase($thisFeed['text'], $thisFeed['title'], "folder", "", "");
foreach($thisFeed->outline as $feeds) {
$DB->addFeedToDatabase($feeds['text'], $feeds['title'], $feeds['type'], $feeds['xmlUrl'], $feeds['htmlUrl']);
}
echo "<br /><br />";
}
}
}
} //end importRSSFeeds($xmlFile)
//Get the feeds from the database and display them on the left for the user.
public function getFeedList() {
$lastType = "";
$DB = new Database();
$result = $DB->returnFeedList();
foreach($result as $individualFeed) {
if($individualFeed['type'] == "folder") {
if ($lastType == "rss") {
echo "</ul></div>";
}
echo "<li><i class=\"icon-folder-close\"></i>" . $individualFeed['title'] . "</li>";
echo "<div class=\"collapse in\" id=\"" . str_replace(" ", "", $individualFeed['title']) . "\">";
echo "<ul class=\"nav nav-list\">";
} else if($individualFeed['type'] == "rss") {
echo "<li>" . $individualFeed['title'] . "</li>";
}
$lastType = $individualFeed['type'];
}
$DB->closeDatabaseConnection();
}
}//end class RSSFeed
When checking the javascript alerts, it is triggering the success: case but not returning the echo'd data. What piece am I missing to have the SimplePie class return the correct, echo'd data via AJAX to my id="feedBody" div? What am I missing?
EDIT:
Firebug says the following regarding the XHR:
//Response Headers
Status: 200 OK
Connection Keep-Alive
Content-Length 0
Content-Type text/html
Date Thu, 11 Apr 2013 19:54:33 GMT
Keep-Alive timeout=5, max=100
Server Apache
X-Powered-By PHP/5.4.4
//Request Headers
Accept text/html, */*; q=0.01
Accept-Encoding gzip, deflate
Accept-Language en-US,en;q=0.5
Cookie __utma=111872281.446718044.1365710024.1365710024.1365710024.1; __utmb=111872281.2.10.1365710024; __utmc=111872281; __utmz=111872281.1365710024.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)
DNT 1
Host localhost:8888
Referer http://localhost:8888/Charcoal-Bootstrap_RSSReader/
User-Agent Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:20.0) Gecko/20100101 Firefox/20.0
X-Requested-With XMLHttpRequest
Params appear to be passing over correctly (just one example):
url http://iphone.keyvisuals.com/feed/
Full index.php: http://pastebin.com/UJiFuBvG
Full RSSFeed.php: http://pastebin.com/CGU2nQHB
Full main.js (handles the AJAX): http://pastebin.com/1pPQuPUx
Thanks!
The answer came when I really pushed the alerts/exceptions to debug it and it seems as though it was not correctly loading the simplepie file, thus causing a fatal error and it to die. Sorry about that! Thank you Brad though