Facebook Graph API PHP SDK v4 - Post on Page - php

I wanna give all my website authors a possiblity to post their articles on our facebook page without having go give them admin access to it.
So i created a simple form, where the author types in: URL, URL to image, message
On submit, this form will send a ajax request to facebook.php where the magic "should" happen.
The first problem occurs at "require_once".
It's not possible to require all 4 files without having an error.
If i get rid of the facebook exception, then everything works except the request itself.
There seems to be an PHP Error, because i get no ajax response at all.
session_start();
require_once($_SERVER['DOCUMENT_ROOT'].'/sys/facebook/FacebookSession.php');
require_once($_SERVER['DOCUMENT_ROOT'].'/sys/facebook/FacebookRequest.php');
require_once($_SERVER['DOCUMENT_ROOT'].'/sys/facebook/GraphObject.php');
require_once($_SERVER['DOCUMENT_ROOT'].'/sys/facebook/FacebookRequestException.php');
use Facebook\FacebookSession;
use Facebook\FacebookRequest;
use Facebook\GraphObject;
use Facebook\FacebookRequestException;
$message = safe($_POST["message"]);
$url = safe($_POST["url"]);
$image = safe($_POST["image"]);
if($message == "" OR $url == "" OR $image == ""){
echo "incomplete";
return;
}
FacebookSession::setDefaultApplication('{APP ID}','{APP SECRET}');
$session = new FacebookSession('{Page Access Token}');
if($session) {
try {
$response = (new FacebookRequest(
$session, 'POST', '/{Page ID}/feed', array(
'message' => $message,
'link' => $url,
'picture' => $image
)
))->execute()->getGraphObject();
echo "Posted with id: " . $response->getProperty('id');
} catch(FacebookRequestException $e) {
echo "Exception occured, code: " . $e->getCode();
echo " with message: " . $e->getMessage();
}
} else {
echo "No Session available!";
}

Update: June, 27 2014, The SDK now comes with a built-in autoloader for those who can't use composer.
require __DIR__ . '/path/to/facebook-php-sdk-v4/autoload.php';
If that doesn't automatically find the path for you, you can define it with FACEBOOK_SDK_V4_SRC_DIR.
define('FACEBOOK_SDK_V4_SRC_DIR', '/path/to/facebook-php-sdk-v4/src/Facebook/');
require __DIR__ . '/path/to/facebook-php-sdk-v4/autoload.php';
The internals of the SDK rely on several other classes that you're not including. That's why autoloading is really important here.
Autoloading With Composer
The best way to do this is to install composer. And add the SDK in a composer.json file to the root of your project.
{
"require" : {
"facebook/php-sdk-v4" : "4.0.*"
}
}
Then run composer install from the command line where the composer.json file is. Then include the autoloader at the top of your script.
require_once __DIR__ . '/vendor/autoload.php';
Manual Autoloading
An alternative way to autoload these files is to replace your require_once's at the top with this solution from rm-vanda:
function facebookLoader($class) {
require "/path/to/facebook-php-sdk-v4-master/src/" . str_replace("\\", "/", $class) . ".php";
}
spl_autoload_register("facebookLoader");

Here I got my solution fixing on updating the Facebook Graph SDK, I do apologize for the short answer.
I updated, php.ini file and enabled, the fileinfo extension by uncommenting
;extension=fileinfo
Removing the ; tag to
extension=fileinfo
Then do the command,
composer update
Credits: StackOverflow, Bing, and Google search.
Warning: I'm using, Laravel, Wnmp as a local webserver.
Note: This comment may require revisions.

Related

Solutions to traylabs/oracle-storage PHP web API Integration

There is a piece of code which keeps throwing this error:
RuntimeException: SplFileObject::__construct(86a03f5ac14227ae4e596750c3a90db1612f77ce1b00e4aa6cbd4b2dc5e69835.icturee.jpg): failed to open stream: No such file or directory in /home/site/vendor/tray-labs/oracle-storage/src/Object/File.php:42 Stack trace: #0 /home/site/vendor/tray-labs/oracle-storage/src/Object/File.php(42): SplFileObject->__construct('86a03f5ac14227a...') #1 /home/site/vendor/tray-labs/oracle-storage/src/Service/UploadService.php(25): TrayLabs\OracleStorage\Object\File->getFile() #2 /home/site/vendor/tray-labs/oracle-storage/src/OracleStorage.php(64): TrayLabs\OracleStorage\Service\UploadService->handle('86a03f5ac14227a...', Object(TrayLabs\OracleStorage\Object\File)) #3 /home/site/includes/storageProcessor.php(15): TrayLabs\OracleStorage\OracleStorage->upload('86a03f5ac14227a...', Object(TrayLabs\OracleStorage\Object\File)) #4 /home/site/wwwroot/chumba.html(470): storeFile(Object(TrayLabs\OracleStorage\OracleStorage), '86a03f5ac14227a...', '86a03f5ac14227a...') #5 {main}
I have tried my best to follow the integration document of the traylabs\oracle-storage package like:
Add this line in composer.json file in the web app project's root folder
require traylabs/oracle-storage
Execute this command to install the package in the vendors directory
php composer.phar update
Create the configuration file conf.php
return [ 'user'=>[
'username'=>'example#gmail.com',
'password'=>'#password'
], 'account'=>[
'identifier'=>'bucket',
'auth_url'=>'https://oraclecloud.com/object-storage/buckets/f4yay/items'
], 'storage'=>[
'container'=>'items',
'local_path'=>'/home/site/wwwroot/destination/',
'cache'=>true
] ];
creating the processing.php file for encapsulating the file upload to cloud functionality as shown:
<?php
use \TrayLabs\OracleStorage\OracleStorage;
use \TrayLabs\OracleStorage\Object\File;
use \TrayLabs\OracleStorage\ExceptionFileNotFound;
require_once("../vendor/autoload.php");
function getClient() {
$client=new OracleStorage(require '/home/site/includes/Conf.php');
return $client;
}
//utility
function storeFile($client,$filename) {
$calledname=$client->upload("$filename", new File($filename));
return $calledname;
}
?>
include the processing.php file via require_once() function in several products.html files from which image files i.e jpeg/ping etc will be uploaded to the web app server and later to the oracle cloud object storage as shown here under:
<?php
use \TrayLabs\OracleStorage\OracleStorage;
use \TrayLabs\OracleStorage\Object\File;
use \TrayLabs\OracleStorage\ExceptionFileNotFound;
require_once('./../includes/processing.php');
require_once("./../vendor/autoload.php");
if ($_SERVER["REQUEST_METHOD"]=="POST")
{
if ($_FILES['picha']['error'] == UPLOAD_ERR_OK)
{
$tmpName = $_FILES['picha']['tmp_name'];
$name = basename($_FILES['picha']['name']);
$ext = strtolower(substr($name, strripos($tmpName, '.')+1));
$filename = hash_file('sha256', $tmpName) . '.' . $ext;
$destination=__DIR__."/warehouse/$filename";
$message=move_uploaded_file($tmpName,$destination);
$filepath=$destination;
$contents=fopen($filepath,'r');//getfilecontents($filepath);
try
{
$client=new getClient();
$itemname=storeFile($client,$filename);
}
catch(Exception $ex)
{
$ex->getMessage();
echo $ex;
}
unlink($destination);
//some more code goes here
}
}
?>
For brevity I have removed some code such as html form elements and other associated data element for particular product
I have got the solution. I remembered something that I should put on the checklist. I simply went to the kudu console for my app which is hosted in azure app service and changed the owner of folder where I kept the multimedia files to www-data and soon after that retest my app it is running smoothly as it supposed to do.

In PHP, when autoloading files, where PHP will look for these files?

I have an MVC-based application with a basic URL-rewriting rule, which makes the URL look like this: website/controller/action/id. The id is optional.
If a user enters an invalid action, he should get an error which is handled in the class ErrorController.
All of my classes files are required in an autoloader file, so I should not require them every time I want to create an object. I use spl_autoload_register() for autoloading.
The problem occurs when I try to entering a URL with an invalid action. For example, for the URL website/main/inde (instead of index) - an instance of ErrorController should be created.
Instead, I get this two PHP errors:
Warning: require(!core/errorcontroller.php): failed to open stream: No
such file or directory in
D:\Programs\Wamp\www\fanfics\v0.0.2!core\autoloader.php on line 5
And
Fatal error: require(): Failed opening required
'!core/errorcontroller.php' (include_path='.;C:\php\pear') in
D:\Programs\Wamp\www\fanfics\v0.0.2!core\autoloader.php on line 5
Here is a visual of my files (the exclamation mark before the core folder is for keeping it on the top):
index.php:
<?php
require "!core/autoloader.php";
$loader = new Loader();
!core/autoloader.php
<?php
function autoload_core_classes($class)
{
require "!core/" . strtolower($class) . ".php";
}
function autoload_controllers($class)
{
require "controllers/" . str_replace("controller", "", strtolower($class)) . ".php";
}
function autoload_models($class)
{
require "models/" . str_replace("model", "", strtolower($class)) . ".php";
}
spl_autoload_register("autoload_core_classes");
spl_autoload_register("autoload_controllers");
spl_autoload_register("autoload_models");
!core/basecontroller.php
<?php
abstract class BaseController
{
protected $model;
protected $view;
private $action;
public function __construct($action)
{
$this->action = $action;
$this->view = new View(get_class($this), $action);
}
public function executeAction()
{
if (method_exists($this->model, $this->action))
{
$this->view->output($this->model->{$this->action}());
}
else
{
// Here I create an ErrorController object when the action is invalid
$error = new ErrorController("badmodel");
$error->executeAction();
}
}
}
If I try to require controllers/error.php specifically - it works just fine:
.
.
.
else
{
require "controllers/error.php"; // With this line it works just fine
$error = new ErrorController("badmodel");
$error->executeAction();
}
After an online really long search, I understand that there is maybe a problem with the include_path, but I do not quite understand it. How can I solve this problem?
It's a good idea for each autoloader function to check if the file exists before blindly trying to include/require it. Autoloaders are not expected to throw any errors and should fail silently so they can allow the next autoloader in the queue to attempt to autoload the necessary files.
<?php
function autoload_core_classes($class)
{
if (is_readable("!core/" . strtolower($class) . ".php"))
include "!core/" . strtolower($class) . ".php";
}
function autoload_controllers($class)
{
if (is_readable("controllers/" . str_replace("controller", "", strtolower($class)) . ".php"))
include "controllers/" . str_replace("controller", "", strtolower($class)) . ".php";
}
function autoload_models($class)
{
if (is_readable( "models/" . str_replace("model", "", strtolower($class)))
include "models/" . str_replace("model", "", strtolower($class)) . ".php";
}
spl_autoload_register("autoload_core_classes");
spl_autoload_register("autoload_controllers");
spl_autoload_register("autoload_models");
PHP searches for inclusions in paths defined into the property include_path. For command line you can check its value with:
php -i | grep include_path
For web check it with:
phpinfo()
In any case you can modify the value within php.ini.
I used to chdir() in the root of the project in my single entry point and then include files with relative path from root. This is working because include_path usually contains the current directory "."

Yii2 How to use external PHP libraries

I want to use https://github.com/HelloFax/hellosign-php-sdk in Yii2 project so I followed following step
1 ) updated composer.json with "hellosign/hellosign-php-sdk": "3.*#dev" in require section
2) run composer update in CMD (I work with window 7)
so it downloaded required libraries (hellosign-php-sdk and libary) in vendor
3 ) include following code in controller file
$client = new HelloSign\Client('df754dd564e52fb2891a60eb2fea777b5320397********');
$response = $client->getSignatureRequest('f6197945000616b383d4752*****');
if ($response->isComplete()) {
echo 'All signers have signed this request.';
} else {
foreach ($response->getSignatures() as $signature) {
echo $signature->getStatusCode() . "\n";
}
}
Error
Unable to find 'app\controllers\HelloSign\Client' in file: C:\wamp\www\yii2hellosign/controllers/HelloSign/Client.php. Namespace missing?
How to solve this issue, any help ?
the library use psr-0 autoload, so you need to prepend classname with \ , like this:
$client = new \HelloSign\Client('...');

how to start using composer at a project that has autoload function?

I have a project that was developed without namespaces and with a "private framework" written by my team at the time. Said framework depends on an autoload function that includes files from within the framework and automatically finds files inside the project, which means that inside the project we have 0 includes/requires. Every file follows a specific rule and gets included by my function.
Everytime we would use third-party library, we would download the files and place them at a specific place and work on getting the files property loaded.
This week I found a new library I wanted to use, so I decided to install it via composer. Now my autoload function doesn't exist and my framework stops any execution at the begin for missing files.
How do I go about keeping my autoload as is (that includes files without namespaces from my project and my framework) and still use composer? Is it possible or I'm dead?
Edit: Adding some files to the question.
frameworkBootstrap - This file loads the framework (works just fine).
<?php
$dir = dirname(__FILE__);
// Database Package
require $dir . '/nav/database/NavDao.php';
require $dir . '/nav/database/NavDatabase.php';
require $dir . '/nav/database/NavTable.php';
// General
require $dir . '/nav/general/NavLanguage.php';
require $dir . '/nav/general/NavProject.php';
require $dir . '/nav/general/NavController.php';
// Tool
require $dir . '/nav/tool/NavValidator.php';
require $dir . '/nav/tool/NavLogger.php';
require $dir . '/nav/tool/NavListener.php';
require $dir . '/nav/tool/NavFile.php';
require $dir . '/nav/tool/NavEmail.php';
require $dir . '/nav/tool/NavException.php';
// View
require $dir . '/nav/view/NavPage.php';
require $dir . '/nav/view/NavTemplate.php';
require $dir . '/nav/view/NavView.php';
// Request
require $dir . '/nav/request/NavRequest.php';
require $dir . '/nav/request/NavAccess.php';
require $dir . '/nav/request/NavResponse.php';
require $dir . '/nav/request/NavSession.php';
// Plugin
NavProject::plugin(
array(
'NavMail' => $dir . '/nav/plugin/email/NavMail.php',
'NavXPertMailer2006' => $dir . '/nav/plugin/email/NavXPertMailer2006.php',
'NavLog' => $dir . '/nav/plugin/log/NavLog.php',
'NavImage' => $dir . '/nav/plugin/file/NavImage.php',
'NavMysql' => $dir . '/nav/plugin/dbms/NavMysql.php',
'NavOracle' => $dir . '/nav/plugin/dbms/NavOracle.php',
'NavTranslate' => $dir . '/nav/plugin/translate/NavTranslate.php'
));
require $dir . '/vendor/autoload.php';
?>
Autoload funciton - This funciton is being replaced.
function __autoload($className) {
$file = '';
// Auto Load Template
if (strpos($className, 'Template') !== false)
$file = NavProject::path() . 'class/view/template/' . $className . '.php';
// Auto Load Project Tools
else if (strpos(strtolower($className), strtolower(NavProject::name())) !== false)
$file = NavProject::path() . 'class/tool/' . $className . '.php';
// Auto Load Controllers
else if (strpos($className, 'Controller') !== false)
$file = NavProject::path() . 'class/control/' . $className . '.php';
// Auto Load Nav Plugin
else if (strpos($className, 'Nav') === 0) {
$list = NavProject::plugin();
foreach ($list as $plugin => $location)
if ($plugin == $className)
$file = $location;
// Auto Load Model
} else {
$file = NavProject::path() . 'class/model/' . $className . '.php';
}
if (is_file($file))
require $file;
}
3rd-party library
https://github.com/alexshelkov/SimpleAcl
You should go the slightly longer route and replace your own autoloading with that of Composer.
Short-term you'd be able to use the classmap feature to autoload every existing code:
"autoload": {
"classmap":
["class/view/template/","class/tool/","class/control/","class/model", "nav/"]
}
The classmap should contain every directory that you have classes in, and the path should be relative from the top level directory where you place your own composer.json.
You'd then remove your own __autoload function (there can be only one defined, and if you do, you cannot have another libraries autoloading active at the same time - the way to do autoloading even long before Composer was to use the "spl_autoload" feature), and you'd also remove every require statement in your framework bootstrap, and replace it with require "vendor/autoload.php";. After autoloading is included, you have access to every class in the classmap of your own code, and to every library you add.
You have to run composer install once to create the classmap.
If you create new classes after this, you again have to run composer dump-autoload to refresh the map. If this gets annoying to you, think about switching to using PSR-0 autoloading instead. I think it's doable with your code base already, but I'm reluctant to suggest something without knowing what your class naming conventions really are.
For example, the autoloader will assume that any class that has "Template" SOMEWHERE in it's name is located in the "class/view/template" folder. This includes TemplateHomepage as well as HomepageTemplate as well as PageTemplateHome. Your autoloader allows for a multitude of names to be loaded, but I suppose you are only using one scheme.
Try replacing __autoload with spl_autoload_register();
Why?
__autoload(); is discouraged and may be deprecated or removed in
the future from docs.
This function can collide with spl_autoload_register() which is used by composer.
spl_autoload_register('my_autoload', false, true);
Then replace __autoload to my_autoload.

how to include php file contains 'use' command in another file with class

I have two files.
in the first file (Facebook.php) i take user data via Facebook (Facebook access token):
<?php
require_once '../include/Config.php';
require_once ( '../libs/facebook/autoload.php' );
use Facebook\FacebookSession;
use Facebook\FacebookRequest;
use Facebook\FacebookRequestException;
function getUserData($token){
// init app with app id and secret
FacebookSession::setDefaultApplication( FB_APP_ID,FB_APP_SECRET ); //
// If you already have a valid access token:
$session = new FacebookSession($token); // 'access-token'
// To validate the session:
try {
$session->validate();
} catch (FacebookRequestException $ex) {
// Session not valid, Graph API returned an exception with the reason.
echo $ex->getMessage();
} catch (\Exception $ex) {
// Graph API returned info, but it may mismatch the current app or have expired.
echo $ex->getMessage();
}
if($session) {
try {
$user_profile = (new FacebookRequest( $session, 'GET', '/me'))->execute()->getGraphObject()->asArray(); //(GraphUser::className());
// print profile data
echo '<pre>' . print_r( $user_profile, 1 ) . '</pre>';
return $user_profile;
} catch(FacebookRequestException $e) {
echo "Exception occured, code: " . $e->getCode();
echo " with message: " . $e->getMessage();
}
}
}
?>
and this is the second file for manage user data:
<?php
require_once '../../../include/Facebook.php';
class userManager {
function __construct() {
}
/**
* Get user data from facebook
* #param user key
* #return user data if exist else false
*/
public function facebookSignIn($token){
$fbUserData = getUserData($token);
print_r($fbUserData);
}
}
?>
in the second file i want to manage user data with a class but i think that my script don't run because the code lines in Facebook.php
use Facebook\FacebookSession;
use Facebook\FacebookRequest;
use Facebook\FacebookRequestException;
causing an error in compiling time.
if I comment out these lines my script compiles but naturally doesn't retrieve facebook user data.
what is the right way to include 'facebook.php' in my class?
where am I wrong?
I apologize but I do not understand 'use' command and how I can use it.
If i include Facebook.php in a test file without class:
<?php
require_once '../include/Facebook.php';
$token = $_GET["token"];
getUserData($token);
?>
the script run fine!
i found a solution for my problem. The problem is in the include lines in the first file because test.php is in different hierarchy path of second file.
I found the error using these lines of code:
error_reporting(E_ALL);
ini_set('display_errors', 1);
I apologize, but sometimes the most obvious things that are beyond our control.
thanks to everyone for the support
I ran into this problem myself early on because I was not accustomed to using these commands. Use commands have to be used within the same file that the functions relative to them are called. So if File A contains the SDK initialization and you try the use commands then your API requests should work. If File B is required or included within File A (or vice-versa), you must add the use commands within File B to initiate any Graph functions but they should still work. It seems use commands only work within the file for which they are located and no others.
In your second file, add the use commands that you need and I believe you'll find it will work. In your specific case, you may also need it within your function.

Categories