Im using Slim Framework as an API. Im making a GET request to it. But I cannot get the headers. My PHP file looks like:
require 'Slim/Slim.php';
$app = new Slim();
$app->get('/project/:id', add_authorize(), 'getProject');
$app->run();
function getProject($project_title) {
//connect to database and return project details
}
function add_authorize() {
return function (){
$app = Slim::getInstance();
$charset = $app->request->headers->get('ACCEPT_CHARSET');
};
}
I get the response:
( ! ) Fatal error: Cannot access protected property Slim::$request in C:\wamp\www\server\device_api\index.php on line 23
Call Stack
# Time Memory Function Location
1 0.0010 248528 {main}( ) ..\index.php:0
2 0.0240 860056 Slim->run( ) ..\index.php:9
3 0.0240 878816 Slim_Route->dispatch( ) ..\Slim.php:1052
4 0.0240 878864 call_user_func:{C:\wamp\www\server\device_api\Slim\Route.php:387} ( ) ..\Route.php:387
5 0.0240 878944 {closure:C:\wamp\www\server\device_api\index.php:19-25}( ) ..\Route.php:387
I have tried absolutely everything but to no avail. I also tried getting headers directly with:
$device_id = $_SERVER['HTTP_DEVICE_ID'];
but this also failed. Any ideas how I can get a header?
Not sure if it's because of your PHP version / Slim version. This is my composer.json file:
"require": {
"slim/slim": "2.3.*"
}
I'm using PHP 5.5.14 on Mac OSX Yosemite. But anyway, try this:
// closure callback
function getProject($id)
{
// connect to database and return project details
// var_dump($id);
}
// act as a middleware, the first argument is \Slim\Route
function addAuthorize($route)
{
// var_dump($route); // \Slim\Route
$app = Slim::getInstance();
$request = $app->request();
$charset = $request->headers->get('ACCEPT_CHARSET');
}
$app->get('/project/:id', 'addAuthorize', 'getProject');
// Turn on the light
$app->run();
I suggest to do the following and not wrap things in a closure:
require 'Slim/Slim.php';
$app = new Slim();
$app->get('/project/:id', add_authorize(), 'getProject');
$app->run();
function getProject($project_title) {
//connect to database and return project details
}
function add_authorize() use ($app) {
$charset = $app->request->headers->get('ACCEPT_CHARSET');
}
The problem is that you are trying to get HTTP Headers like this
$app->request->headers->get('ACCEPT_CHARSET');
And that works after Slim version 2.x. You probably have a previous version, like 1.x.
The previous way to access the HTTP Headers was like this, without the getter:
$app->request->headers('ACCEPT_CHARSET');
You could simply change that in your code or move onto a new version of Slim.
In example here's the Slim Documentation for version 1.6.7
https://github.com/codeguy/Slim/blob/1.6.7/docs/request-headers.markdown
Related
I have this error with Zend (v1) XmlRpc client :
Uncaught exception 'Zend_XmlRpc_Client_FaultException' with message 'Failed to parse response'.
It's the error status 651.
The call never reaches the class/method requested, it seems that the call is not fired like it was blocked or something. I'm in debug on the method called and it's not triggered.
PHP version is 5.4.
EDIT
Here is the code :
Caller class :
require_once 'library/Zend/XmlRpc/Client.php';
class FrontService
{
private $client;
public function __construct($xmlRpc)
{
$this->client = new Zend_XmlRpc_Client($xmlRpc);
}
public function call($name, $params = array())
{
return $this->client->call($name, $params);
}
}
Call to the class :
$this->_fs = new FrontService(HM_Config::getParam("amf-url"));
$editos = $this->_fs->call('getEdito',$params_home);
Code called :
include_once realpath(dirname(__FILE__) .'/..')
.'/application/bootstrap.php';
require_once '_config.php';
require_once 'DirectDbConnectionV2.php';
class FrontGateway extends DirectDbConnectionV2
{
public static $smStatic;
function __construct()
{
mysql_query("SET NAMES 'utf8'");
$this->sm = self::$smStatic;
$this->log = new Log();
$this->log->set_file('amfDbConnection');
$this->log->write('construct bordel');
}
}
FrontGateway::$smStatic = $sm;
$controllerManager = $sm->get('EditoWebsiteMVC\ControllerManager');
$controllerManager->run('EditoWebsite\Controller\UIGateway', 'xmlRpc');
Code that should be executed :
namespace EditoWebsite\Controller;
use EditoWebsiteMVC\AbstractController;
use EditoWebsiteMVC\ViewRender\CLI as CLIViewRender;
use EditoWebsiteMVC\ViewRender\HTMLTemplate as HTMLTemplateViewRender;
use Zend_XmlRpc_Server as XmlRpcServer;
class UIGatewayController extends AbstractController
{
public function xmlRpcAction()
{
$svr = new XmlRpcServer();
$svr->setClass('FrontGateway');
echo $svr->handle();
exit;
}
}
The code in the getEdito method from the DirectDbConnectionV2 is never reached.
Is there something I need to enable on the server ? or a port that I need to open ?
EDIT EDIT
I should mention that the code is working on another server that I've access to, is there anything I should compare / check to maybe solve that issue ?
Thanks a lot
I don't think there's enough info to even make a guess, but let me try.
I've faced similar issue, where requests sent never reached the server. It turned out to be that Zend_Http_Client_Adapter_Socket adapter is binding to an IPv6 and due to routing issues request never got to the server.
In the end, what solved the issue was:
$client->getAdapter()->setStreamContext(array(
'socket' => array('bindto' => '0:0'),
));
where $client is an instance of Zend_Http_Client.
Again, it's just a shot in the dark, but could be worth trying. :)
Edit:
In your case, you should add following to FrontService constructor:
$this->client->getHttpClient()->getAdapter()->setStreamContext(array(
'socket' => array('bindto' => '0:0'),
));
Edit Edit:
Since back on 1.9.0 there's no getAdapter on Zend_Http_Client, you have to create adapter yourself and pass it to http client:
public function __construct($xmlRpc)
{
$this->client = new Zend_XmlRpc_Client($xmlRpc);
$adapter = Zend_Http_Client_Adapter_Socket();
$adapter->setStreamContext(array(
'socket' => array('bindto' => '0:0'),
));
$this->client->getHttpClient()->setAdapter($adapter);
}
Cheers.
I've a problem using elasticsearch in a php application. The application is built with zend and uses a .env to hold the following configuration:
ELASTICSEARCH_MAX_DOCUMENTS=250
ELASTICSEARCH_MAX_BULK_SIZE=3M
ELASTICSEARCH_HOST=my-elasticsearch.intern.rz
ELASTICSEARCH_PORT=80
ELASTICSEARCH_USER=user
ELASTICSEARCH_PASSWORD=pw
The call to index the new files is part of a import service class and looks like this:
public function flush(FlushInterface $flushInterface = null) {
$bulk = $this->getSearchDocumentBulk();
if (!empty($bulk->getActions())) {
$response = $bulk->send();
$this->resetSearchDocumentBulk();
if (0 === $response->count()) {
$data = $response->getData();
throw new BulkException(isset($data['message']) ? strip_tags($data['message']) : '');
}
}
$this->documentCache = [];
if ($flushInterface instanceof FlushInterface) {
$flushInterface->flush();
}
return $this;
}
protected function getSearchDocumentBulk() {
if (!($this->searchDocumentBulk instanceof Bulk)) {
$this->searchDocumentBulk = new Bulk($this->getSearchClient()->getClient());
$this->searchDocumentBulk->setIndex(self::INDEX);
}
return $this->searchDocumentBulk;
}
I know it's only a short snippet but it's quite difficult to pull out the relevant code. So please let me know if I have to post some more methods.
The application is started by a symfony command and I'm able to curl to elasticsearch (version 5.1) without any errors.
My problem is that no document is indexed. If I check elasticsearch-head I see that there was no data transfer anymore.
But there's also no error, no exception or something like that. The process is completed with 100% (100,000 of 100,000 files imported). So I've no idea what happens or how to find out the bug.
I am integrating quickbooks with my laravel app. After integration I got this error,
PHP Warning: require_once(../QuickBooks.php): failed to open stream:
No such file or directory in
/home/vipin/projects/development/Quickbook/config/app.php on line 2
PHP Fatal error: require_once(): Failed opening required '../QuickBooks.php'
(include_path='.:/usr/share/php:/home/ubuntu/projects/development/Quickbook/vendor/consolibyte/quickbooks')
in /home/ubuntu/projects/development/Quickbook/config/app.php on line
2
Here is my controller Quickbook.php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
// require_once '../QuickBooks.php';
use App\Http\Requests;
class QuickBooksController extends Controller
{
private $IntuitAnywhere;
private $context;
private $realm;
public function __construct(){
if (!\QuickBooks_Utilities::initialized(env('QBO_DSN'))) {
// Initialize creates the neccessary database schema for queueing up requests and logging
\QuickBooks_Utilities::initialize(env('QBO_DSN'));
}
$this->IntuitAnywhere = new \QuickBooks_IPP_IntuitAnywhere(env('QBO_DSN'), env('QBO_ENCRYPTION_KEY'), env('QBO_OAUTH_CONSUMER_KEY'), env('QBO_CONSUMER_SECRET'), env('QBO_OAUTH_URL'), env('QBO_SUCCESS_URL'));
}
public function qboConnect(){
if ($this->IntuitAnywhere->check(env('QBO_USERNAME'), env('QBO_TENANT')) && $this->IntuitAnywhere->test(env('QBO_USERNAME'), env('QBO_TENANT'))) {
// Set up the IPP instance
$IPP = new \QuickBooks_IPP(env('QBO_DSN'));
// Get our OAuth credentials from the database
$creds = $this->IntuitAnywhere->load(env('QBO_USERNAME'), env('QBO_TENANT'));
// Tell the framework to load some data from the OAuth store
$IPP->authMode(
\QuickBooks_IPP::AUTHMODE_OAUTH,
env('QBO_USERNAME'),
$creds);
if (env('QBO_SANDBOX')) {
// Turn on sandbox mode/URLs
$IPP->sandbox(true);
}
// This is our current realm
$this->realm = $creds['qb_realm'];
// Load the OAuth information from the database
$this->context = $IPP->context();
return true;
} else {
return false;
}
}
public function qboOauth(){
if ($this->IntuitAnywhere->handle(env('QBO_USERNAME'), env('QBO_TENANT')))
{
; // The user has been connected, and will be redirected to QBO_SUCCESS_URL automatically.
}
else
{
// If this happens, something went wrong with the OAuth handshake
die('Oh no, something bad happened: ' . $this->IntuitAnywhere->errorNumber() . ': ' . $this->IntuitAnywhere->errorMessage());
}
}
public function qboSuccess(){
return view('qbo_success');
}
public function qboDisconnect(){
$this->IntuitAnywhere->disconnect(env('QBO_USERNAME'), env('QBO_TENANT'),true);
return redirect()->intended("/yourpath");// afer disconnect redirect where you want
}
public function createCustomer(){
$CustomerService = new \QuickBooks_IPP_Service_Customer();
$Customer = new \QuickBooks_IPP_Object_Customer();
$Customer->setTitle('Ms');
$Customer->setGivenName('Shannon');
$Customer->setMiddleName('B');
$Customer->setFamilyName('Palmer');
$Customer->setDisplayName('Shannon B Palmer ' . mt_rand(0, 1000));
// Terms (e.g. Net 30, etc.)
$Customer->setSalesTermRef(4);
// Phone #
$PrimaryPhone = new \QuickBooks_IPP_Object_PrimaryPhone();
$PrimaryPhone->setFreeFormNumber('860-532-0089');
$Customer->setPrimaryPhone($PrimaryPhone);
// Mobile #
$Mobile = new \QuickBooks_IPP_Object_Mobile();
$Mobile->setFreeFormNumber('860-532-0089');
$Customer->setMobile($Mobile);
// Fax #
$Fax = new \QuickBooks_IPP_Object_Fax();
$Fax->setFreeFormNumber('860-532-0089');
$Customer->setFax($Fax);
// Bill address
$BillAddr = new \QuickBooks_IPP_Object_BillAddr();
$BillAddr->setLine1('72 E Blue Grass Road');
$BillAddr->setLine2('Suite D');
$BillAddr->setCity('Mt Pleasant');
$BillAddr->setCountrySubDivisionCode('MI');
$BillAddr->setPostalCode('48858');
$Customer->setBillAddr($BillAddr);
// Email
$PrimaryEmailAddr = new \QuickBooks_IPP_Object_PrimaryEmailAddr();
$PrimaryEmailAddr->setAddress('support#consolibyte.com');
$Customer->setPrimaryEmailAddr($PrimaryEmailAddr);
if ($resp = $CustomerService->add($this->context, $this->realm, $Customer))
{
//print('Our new customer ID is: [' . $resp . '] (name "' . $Customer->getDisplayName() . '")');
//return $resp;
//echo $resp;exit;
//$resp = str_replace('{','',$resp);
//$resp = str_replace('}','',$resp);
//$resp = abs($resp);
return $this->getId($resp);
}
else
{
//echo 'Not Added qbo';
print($CustomerService->lastError($this->context));
}
}
public function addItem(){
$ItemService = new \QuickBooks_IPP_Service_Item();
$Item = new \QuickBooks_IPP_Object_Item();
$Item->setName('My Item');
$Item->setType('Inventory');
$Item->setIncomeAccountRef('53');
if ($resp = $ItemService->add($this->context, $this->realm, $Item))
{
return $this->getId($resp);
}
else
{
print($ItemService->lastError($this->context));
}
}
public function addInvoice($invoiceArray,$itemArray,$customerRef){
$InvoiceService = new \QuickBooks_IPP_Service_Invoice();
$Invoice = new \QuickBooks_IPP_Object_Invoice();
$Invoice = new QuickBooks_IPP_Object_Invoice();
$Invoice->setDocNumber('WEB' . mt_rand(0, 10000));
$Invoice->setTxnDate('2013-10-11');
$Line = new QuickBooks_IPP_Object_Line();
$Line->setDetailType('SalesItemLineDetail');
$Line->setAmount(12.95 * 2);
$Line->setDescription('Test description goes here.');
$SalesItemLineDetail = new QuickBooks_IPP_Object_SalesItemLineDetail();
$SalesItemLineDetail->setItemRef('8');
$SalesItemLineDetail->setUnitPrice(12.95);
$SalesItemLineDetail->setQty(2);
$Line->addSalesItemLineDetail($SalesItemLineDetail);
$Invoice->addLine($Line);
$Invoice->setCustomerRef('67');
if ($resp = $InvoiceService->add($this->context, $this->realm, $Invoice))
{
return $this->getId($resp);
}
else
{
print($InvoiceService->lastError());
}
}
public function getId($resp){
$resp = str_replace('{','',$resp);
$resp = str_replace('}','',$resp);
$resp = abs($resp);
return $resp;
}
}
Config/app.php
<?php
require_once '../QuickBooks.php';
return [
'qbo_token' => env('QUICKBOOK_TOKEN'),
'qbo_consumer_key' => env('QBO_OAUTH_CONSUMER_KEY'),
'qbo_consumer_secret' => env('QBO_CONSUMER_SECRET'),
'qbo_sandbox' => env('QBO_SANDBOX'),
'qbo_encryption_key' => env('QBO_ENCRYPTION_KEY'),
'qbo_username' => env('QBO_USERNAME'),
'qbo_tenant' => env('QBO_TENANT'),
'qbo_auth_url' => 'http://app.localhost:8000/qbo/oauth',
'qbo_success_url' => 'http://app.localhost:8000/qbo/success',
'qbo_mysql_connection' => 'mysqli://'. env('DB_USERNAME') .':'. env('DB_PASSWORD') .'#'. env('DB_HOST') .'/'. env('DB_DATABASE'),
There are several areas to improve on here with the given code & approach.
As Anton correctly points out, you should not be directly requiring any of the quickbooks library files. If you've loaded this in via Composer then they will be automatically loaded because the Composer autoloader will load the QuickBooks file from the vendor. This is correct for Laravel as well as general Composer-based applications - the only difference with Laravel is that there isn't a specific Laravel Package ServiceProvider that's been written for this SDK, but that doesn't matter.
The QuickBooks library tries to jump on top of autoloading any class that starts with 'QuickBooks', so you're better off making a QuickBooks folder for your controller class. This is more of a 'gotcha' and has been pointed out in the repo issues.
The reason you're getting the Driver/.php error is because you have not specified your QBO_DSN, or have done so incorrectly - this DSN environment variable that you're passing to the initialisation is being run through parse_url() in the SDK code, coming up false or null and breaking the auto-loader for initalisation. If this was set to a proper connection string (e.g. mysqli://username:password#host:port/database and note that port must be a number or it's considered malformed), it would correctly process the DSN and continue to load the page. Be aware that initialisation will attempt to parse and fetch the network address of the host, so you can't just put a dummy value in there and expect it to work - this needs to exist first.
You're mixing your environment variables and application configuration, without using either of them properly. If you wanted your DB connection string (a.k.a. QBO_DSN) to be constructed a particular way into the application configuration setting qbo_mysql_connection, then you should be using the configuration setting when trying to initialise/load/etc. Instead of using env('QBO_DSN'), you should be using config('app.qbo_mysql_connection') to load the constructed version from your app settings. Typically you would not be loading so many environment variables into a controller at all - that should be handled by the application, and then the controller calling the application configuration so it's agnostic of how they were defined.
You shouldn't need to require anything from inside the app configuration file either - that file is just for configuration variables being set up.
Since the QuickBooks SDK isn't properly namespaced (yet), there isn't a nice PSR-4 way of loading (and use-ing) the classes, but it's still good practice to use use clauses at the top of the file (e.g. use QuickBooks_Utilities;) so that you can use the classes without fear of forgetting the preceding backslash (i.e. no more \QuickBooks_Utilities, just QuickBooks_Utilities in usage) - there are several instances in the given code where this has been forgotten, and will not work because the Laravel application is namespaced and will look for those classes in the App\Http\Controllers namespace (e.g. errors like "Cannot find class App\Http\Controllers\QuickBooks_Utilities").
Indentation - pick a style (e.g. tabs, 2-space, PSR-2, etc) and then stick to it. Run phpcs or some other clean-up tool over all of your code before committing to your repository or posting on SO - readability is important!
Using require instead of autoloader is a bad practice in modern frameworks (and generally in modern PHP). I highly recommend using the package manager (eg composer) to properly add modules to the project.
For example, to add a quickbooks library into the project using composer, you need to run only one command:
composer require consolibyte/quickbooks
Add this line in footer of Config/app.php
require_once '../QuickBooks.php';
I'm trying to create a soap server in laravel 5.2. This is my code:
Content of SoapController.php:
<?php namespace Giant\Http\Controllers;
class SoapController extends Controller {
public function __construct() {
parent::__construct();
ini_set('soap.wsdl_cache_enabled', 0);
ini_set('soap.wsdl_cache_ttl', 0);
ini_set('default_socket_timeout', 300);
ini_set('max_execution_time', 0);
}
public function server() {
$location = url('server'); // http://payment.dev/server
$namespace = $location;
$class = "\\Giant\\Http\\Controllers\\HelloWorld";
$wsdl = new \WSDL\WSDLCreator($class, $location);
$wsdl->setNamespace($namespace);
if (isset($_GET['wsdl'])) {
$wsdl->renderWSDL();
exit;
}
$wsdl->renderWSDLService();
$wsdlUrl = url('wsdl/server.wsdl');
$server = new \SoapServer(
url('server?wsdl'),
array(
'exceptions' => 1,
'trace' => 1,
)
);
$server->setClass($class);
$server->handle();
exit;
}
public function client() {
$wsdl = url('server?wsdl');
$client = new \SoapClient($wsdl);
try {
$res = $client->hello('world');
dd($res);
} catch (\Exception $ex) {
dd($ex);
}
}
}
class HelloWorld {
/**
* #WebMethod
* #desc Hello Web-Service
* #param string $name
* #return string $helloMessage
*/
public function hello($name) {
return "hello {$name}";
}
}
My wsdl file is: wsdl
And my routes:
Route::any('/server', 'SoapController#server');
Route::any('/client', 'SoapController#client');
And the result I get:
Internal Server Error
:(
I use piotrooo/wsdl-creator to generate wsdl. (There is no problem with that, It is working in laravel 4.2). And I have also tried nusoap and php2wsdl libraries.
My SoapClient is working well. Because it can get service from other soap servers in other urls, But I think my SoapServer can not work well.
I even get no errors in error-log file.
I just figured out wht was the problem:
The problem with log was that i was checking error-log in my www folder while laravel has its own log file. And using that i figured that i have problem with TokenMismatchException. Laravel's CsrfVerifyMiddleware would not letting me to request using soap.
I just added my url to "except" array inside CsrfVerifyMiddleware file.
Do not use two classes in one file
This is my experience from our project in which used Soap
This is SoapServerController . Paste wsdl file in root folder of your project
class SoapServerController extends Controller {
public function service() {
$server = new \SoapServer('http://' . request()->server('HTTP_HOST') . '/yourwsdlfile.wsdl');
$server->setClass('App\Http\Requests\somenamespace\SoapRequest');
$server->handle();
}
}
and in requests create class for requests like this:
class SoapRequest{
public function functionFromWsdl($args if you want) {
$parameters = (array) $args;
return with(new fooClass())->barMethod($parameters);
}
}
and route must be post:
Route::post('webservice','SoapServerController#service');
In laravel 5 all before statements have turned into middlewares (just like what is in django framework). And you need to implement using middlewares.
So after fixing mustache and Apache perms I now have ran into an issue where the site will load the index page, but any page after that located in (the same place a index.html) /pages as it fails to load.
What you can see below is the index.php for Slim to do it's stuff. I can't really understand why the index page will load just fine but no other page will load. If you can point me in the right direction then it would be greatly appreciated.
Examples:
End User > myexample.com/
Location > myexample.com/pages/index.html
The above works just fine but if you look below, you should be able to understand my issue.
End User > myexample.com/info
Location > myexample.com/pages/info.html
The End User is what you see on the site, but the location is where the files belong.
Thanks in advance, Luke.
<?php
// Load up composer autoload, and instantiate the application.
require 'vendor/autoload.php';
$app = new \Slim\Slim;
// Register a singleton of the Mustache engine, and tell it to cache
$app->container->singleton('mustache', function () {
return new Mustache_Engine(array(
'cache' => 'storage',
'loader' => new Mustache_Loader_FilesystemLoader(dirname(__FILE__) . '/pages', array('extension' => '.html'))
));
});
// Helper function to render templates
function renderTemplate($name, $data = array()) {
global $app;
if (file_exists('config.php')) {
$data = (require 'config.php');
}
$data += array(
'resourceUri' => $app->request->getResourceUri() ?: 'index',
'request' => $app->request
);
return $app->mustache->loadTemplate($name)->render($data);
}
// Loads a page by the given name/path
function loadPage($path) {
global $app;
// Set up the base path
$f = 'pages/' . $path;
if (file_exists($f . '.html')) {
// If there's an HTML file, render the mustache template
return renderTemplate($path . '.html');
} elseif (file_exists($f . '.php')) {
// If there's a PHP file, return it
return (require $f . '.php');
} elseif ($path != '404') {
// Otherwise, go get the 404 page
return loadPage('404');
} else {
// But if the user doesn't have a 404 page made, return a plain 404
$app->halt(404);
}
}
// Index page
$app->get('/', function () use ($app) {
echo loadPage('index');
});
// Route to everything else
$app->get('/.*?', function () use ($app) {
// Get the current request path
$path = $app->request->getResourceUri();
// Make sure the user isn't trying to escape and do nasty things
if (!preg_match('/^[A-z\/\-\_]+$/', $path)) {
echo loadPage('404');
}
// Send the page off to get loaded
echo loadPage($path);
});
$app->run();
I think you'll find your problem isn't with Slim but rather with the custom functions you wrote to allow Slim to load Mustache templates.
I would highly recommend removing those functions and using the custom Slim Mustache view provided in the views directory of Slim-Extras repo. At that point, any issues with Slim can be more easily diagnosed as there won't be custom functions to debug.
NOTE: While the Slim-Extras repo is deprecated in favor of the Slim-Views repo, the custom Mustache view (which hasn't made it to the Slim-Views repo) should work fine.
For reference please see the Custom Views section of the Slim documentation.
UPDATE: I've been using Dearon's Slim Mustache library for integration with Slim View in a new app of mine and Justin Hileman's PHP implementation of Mustache. Both are highly recommended and simple to install and configure. Good luck!