PHP Autoloader doesn't work on Ubuntu production server - php

I have to environments i'm working developing my API (PHP based):
Local development: Mac OS Yosemite - running PHP 5.5.20
Production server: Ubuntu server - running PHP 5.5.9
My code uses composer for auto loading as followed:
{
"require": {
"facebook/php-sdk": "#stable",
"everyman/neo4jphp": "dev-master",
"predis/predis": "1.0.1",
"aws/aws-sdk-php": "2.*"
},
"autoload": {
"psr-0": {
"PicoCore\\": "",
"PicoCore\\Authentication\\" : "PicoCore/authentication",
"PicoCore\\Aws\\" : "PicoCore/aws",
"PicoCore\\Cache\\" : "PicoCore/cache",
"PicoCore\\Database\\" : "PicoCore/database",
"PicoCore\\Database\\Managers\\" : "PicoCore/database/managers",
"PicoCore\\Facebook\\" : "PicoCore/facebook",
"PicoCore\\Objects\\" : "PicoCore/objects",
"PicoCore\\Rest\\" : "PicoCore/rest",
"PicoCore\\Configuration\\" : "PicoCore/configuration",
"PicoCore\\Configuration\\Api\\" : "PicoCore/configuration/api",
"PicoCore\\Configuration\\PictureReceiver\\" : "PicoCore/configuration/pictureReceiver",
"PicoCore\\Configuration\\PictureUploader\\" : "PicoCore/configuration/pictureUploader",
"PicoCore\\Scripts\\" : "PicoCore/scripts",
"PicoCore\\Times" : "PicoCore/times"
}
}
}
This is my loading function:
// autoload_namespaces.php #generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'PicoCore\\Times' => array($baseDir . '/PicoCore/times'),
'PicoCore\\Scripts\\' => array($baseDir . '/PicoCore/scripts'),
'PicoCore\\Rest\\' => array($baseDir . '/PicoCore/rest'),
'PicoCore\\Objects\\' => array($baseDir . '/PicoCore/objects'),
'PicoCore\\Facebook\\' => array($baseDir . '/PicoCore/facebook'),
'PicoCore\\Database\\Managers\\' => array($baseDir . '/PicoCore/database/managers'),
'PicoCore\\Database\\' => array($baseDir . '/PicoCore/database'),
'PicoCore\\Configuration\\PictureUploader\\' => array($baseDir . '/PicoCore/configuration/pictureUploader'),
'PicoCore\\Configuration\\PictureReceiver\\' => array($baseDir . '/PicoCore/configuration/pictureReceiver'),
'PicoCore\\Configuration\\Api\\' => array($baseDir . '/PicoCore/configuration/api'),
'PicoCore\\Configuration\\' => array($baseDir . '/PicoCore/configuration'),
'PicoCore\\Cache\\' => array($baseDir . '/PicoCore/cache'),
'PicoCore\\Aws\\' => array($baseDir . '/PicoCore/aws'),
'PicoCore\\Authentication\\' => array($baseDir . '/PicoCore/authentication'),
'PicoCore\\' => array($baseDir . '/'),
'Guzzle\\Tests' => array($vendorDir . '/guzzle/guzzle/tests'),
'Guzzle' => array($vendorDir . '/guzzle/guzzle/src'),
'Everyman\\Neo4j' => array($vendorDir . '/everyman/neo4jphp/lib'),
'Aws' => array($vendorDir . '/aws/aws-sdk-php/src'),
);
When i'm running my code on my local development - it works perfectly, so I pushed it to my remote repository and pull it from the production server.
When i'm trying to run my code in my Production server I receive a Class not found error indicating that my autoloading didn't run properly.
Any ideas what could be the reason ?
UPDATE:
When i'm trying to load the external libs (like AWS) it does work, so the problem is defiantly something with how my folders are being loaded.
UPDATE:
This is the class i'm trying to load from index.php:
<?php
//require Pico Core autoload
require 'core/vendor/autoload.php';
//require Pico Api autoload
require 'vendor/autoload.php';
use PicoCore\Rest\ApiInitializer;
use PicoCore\Configuration\Error;
use PicoApi\Managers\ApiManager;
try {
//initialize the API
ApiInitializer::initialize();
//initialize a new Api with the request
$api = new ApiManager($_REQUEST['request']);
echo utf8_encode($api->processApi());
} catch (Exception $e) {
echo json_encode(Array(Error::jsonErrorField() => $e->getMessage()));
}
This is the error I receive Class 'PicoCore\Rest\ApiInitializer' not found
The structure is:
api
|
core
|
PicoCore
|
folders..
rest
|
ApiInitializer.php
folders...
vender
PicoApi (folder)
vendor (foldeR)
index.php

It's your wrong autoloading definition.
You want to use the class
PicoCore\Rest\ApiInitializer
And you have these files:
api/index.php
api/vendor/... (with your required external dependencies)
api/composer.json (with the autoloading mentioned in your question)
api/core/PicoCore/rest/ApiInitializer.php
And you have this autoloading configured:
"autoload": {
"psr-0": {
"PicoCore\Rest\" : "PicoCore/rest"
}
}
This is a mismatch. When you use the class PicoCore\Rest\ApiInitializer, composer will try to locate an entry with a prefix of that class. It will sucessfully detect that classes with prefix PicoCode\Rest can be found via PSR-0 rules in the directory (relative to the position of composer.json) PicoCore/rest.
First strange thing: There is an additional directory named "core" here, and you seem to include TWO autoloaders. Don't do that, Composer works best with only one autoloader.
Second thing: If I ignore that "core" directory for a bit, the PSR-0 rules state that the classname will be converted to a path - and then be searched in the path given for the prefix.
PicoCore\Rest\ApiInitializer as a path is PicoCore/Rest/ApiInitializer.php (note the uppercase "R" in "Rest"), and the path this is to be found is PicoCore/rest/PicoCore/Rest/ApiInitializer.php.
You don't have this file. And thats why Composer cannot find and load it. And this is even without counting this "core" directory level, it will also not be found if you used two composer.json files, one in api and one in api/core, and the one in api/core was used to find the class.
Suggestions:
Use PSR-4 for every class that is inside a namespace.
Don't lowercase namespace or classname parts for the filesystem.
Shorten your autoloading definition. If you'd rename all those lowercase directories below PicoCore into the proper uppercase variants that are being used in your namespace, you will only need one line of autoloading definition, defining the PicoCore prefix. The rest is done by PSR-4 (or PSR-0).
MacOS is using a case insensitive file system by default, and it is considered a bad thing to switch it to case sensitive: https://apple.stackexchange.com/questions/71357/how-to-check-if-my-hd-is-case-sensitive-or-not That's why it is working on Mac, but not Linux.

Related

How to disable "always include" class in Composer autoload_static.php

Composer in autoload_static.php use class that I don't need them in every app request.
'd5fa61a7f6cbc1df09dd4df84549a2dc' => __DIR__ . '/..' . '/rospdf/pdf-php/src/Cpdf.php',
'2d15964294879de66053d54f6bde65d7' => __DIR__ . '/..' . '/rospdf/pdf-php/src/Cezpdf.php',
How to remove them from this autoload file? I can delete/comment them manually but every Composer update this file is re-generated.
I try to add in my main composer.json:
"exclude-from-classmap": ["vendor/rospdf/pdf-php/src/"]
& run composer dump-autoload bo those class are still in there.
You can trick the autoloader of composer and let him think those are already loaded:
<?php
// Setting global variable:
$GLOBALS["__composer_autoload_files"] = [
"d5fa61a7f6cbc1df09dd4df84549a2dc" => true,
"2d15964294879de66053d54f6bde65d7" => true,
];
require "vendor/autoload.php";
But this needs to happen before the vendor/autoload.php is included.

PHP-intercom not working after updating composer

i recently updated using composer. After updating I am getting error in php file , where I am sending data to intercom. This is the error :
Fatal error: Class 'Intercom\IntercomBasicAuthClient' not found in <filename>
I found a similar problem here Symfony Exception (Class not found) only on development and production servers. But couldn't understand exactly how to solve the issue.
I tried using intercom in Uppercase as well as lowercase, but problem is not solved.
In my installed.json I found this :
"autoload": {
"psr-4": {
"Intercom\\": [
"src"
]
}
}
And this is the directory location of intercom files :
/public_html/vendor/intercom/intercom-php/src
When I dig into more composers file(was trying to understand how classes are included and all), I came across this code in autoload_namespaces.json
<?php
// autoload_namespaces.php #generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'libphonenumber' => array($vendorDir . '/giggsey/libphonenumber-for-php/src'),
'PhpAmqpLib' => array($vendorDir . '/php-amqplib/php-amqplib'),
);
libphonenumber and phpamqplib are two libraries that I installed using composer, and intercom is missing here.
So I am totally confused, what is the actual problem.
Is the intercom library missing in autoload_namespace or is it the uppercase-lowercase issue or what.
Edit :
This I found in autoload_psr4.php
<?php
// autoload_psr4.php #generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-message/src'),
'JmesPath\\' => array($vendorDir . '/mtdowling/jmespath.php/src'),
'Intercom\\' => array($vendorDir . '/intercom/intercom-php/src'),
'GuzzleHttp\\Psr7\\' => array($vendorDir . '/guzzlehttp/psr7/src'),
'GuzzleHttp\\Promise\\' => array($vendorDir . '/guzzlehttp/promises/src'),
'GuzzleHttp\\' => array($vendorDir . '/guzzlehttp/guzzle/src'),
'Aws\\' => array($vendorDir . '/aws/aws-sdk-php/src'),
);
And this is how I am including Intercom in my php file :
use Intercom\IntercomBasicAuthClient;
I figured it out myself.
The problem was with PHP version. I am using php-5.5 and the intercom library strictly requires PHP version >= 5.6 .
Created my own library using Intercom APIs to get it work for php-5.5.

How to call GetId3 classes within a namespaced application

I am sorry if this has once been asked but I lack understanding on how this should work.
I am building a File Server to manage uploading and downloading of music files and have found getID3 library that I can use to get information about the files being uploaded.
I have installed the library via composer. Below is my entry on composer.json in my root director
"james-heinrich/getid3": "dev-master"
Vendor folder was successfully updated with the library.
The library has not been added onto autoload_namespaces.php file in vendor/composer (see below):
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'Symfony\\Component\\Filesystem\\' => array($vendorDir . '/symfony/filesystem'),
'Psr\\Log\\' => array($vendorDir . '/psr/log'),
'GetId3_' => array($vendorDir . '/phansys/getid3'),
);
Also under autoload_psr4.php file in vendor/composer the namespace for the library has not been registered either. I am not sure if this would be the case. Below is the content of the file:
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'Monolog\\' => array($vendorDir . '/monolog/monolog/src/Monolog'),
'FileServer\\' => array($baseDir . '/src'),
);
Question(s)
How can I access the class libraries from getID3? Is there any special operation that I need to perform to make these classes available to me?
NB: The demos folder of the library does not use namespaces but rather "require" to include class files and that in my understanding forfeits the point of composer and namespaces. Resorting to Phansys Symdony library didnt help at all as I was not even sure if the library can be used on standalone projects.
Thanking you in advance.
Command composer dump-autoload is the answer thanks to #Frank.

Ideal project directory structure for web application using Grunt with npm, bundler and composer

I've got a project set up for a web application using Grunt to automate build tasks. I'm using SASS and Compass as well as Composer to manage PHP dependencies. Currently I have a folder structure which looks like this:
-project
|-build
|-node_modules
|-src
| |-composer.json
|Gemfile
|Gruntfile.js
|package.json
This way all of my dependencies for Grunt are configured in package.json and managed by npm, the dependencies for SASS and Compass are configured in the Gemfile and managed by bundler and the dependencies for PHP are configured in composer.json and managed by Composer. Grunt copies over files from the src folder to build during a build, as well as generating/compressing CSS from SASS and minifying js.
I'm wondering if there's a better folder structure for dealing with this as I'd prefer to be able to run all the initial working environment setup from the project root, rather than having to run composer from within src. At the moment I'm keeping it in src in order to generate the autoload path correctly, otherwise it treats the project root as the web root.
Update:
Apologies for the unaccept and for the insufficient explanation. To help clarify below is the content of my composer.json now that it has been moved to the project root, the issue is not with vendor files but with using composer to create an autoloader for project files:
{
"config": {
"vendor-dir": "src/vendor"
},
"repositories": [
{
"type": "composer",
"url": "https://packages.zendframework.com/"
}
],
"require": {
"aws/aws-sdk-php": "2.4.*",
"zendframework/zend-json": "2.0.*"
},
"autoload": {
"psr-0": {"Project\\": "src/include/"}
}
}
Which outputs the following autoload_namespaces.php file inside vendor/composer
// autoload_namespaces.php #generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname(dirname($vendorDir));
return array(
'Zend\\Stdlib\\' => array($vendorDir . '/zendframework/zend-stdlib'),
'Zend\\Json\\' => array($vendorDir . '/zendframework/zend-json'),
'Symfony\\Component\\EventDispatcher\\' => array($vendorDir . '/symfony/event-dispatcher'),
'Guzzle\\Tests' => array($vendorDir . '/guzzle/guzzle/tests'),
'Guzzle' => array($vendorDir . '/guzzle/guzzle/src'),
'Project\\' => array($baseDir . '/src/include'),
'Aws' => array($vendorDir . '/aws/aws-sdk-php/src'),
);
Having the $vendorDir look two levels up with the double dirname call is ok, but the $baseDir is now pointing to the level above src, which is now explicity hardcoded into the autoloader for Project. I suspect the only way to solve this is to move composer.json back into the src folder, or by writing a build script to rewrite this file, which seems nasty. Any alternatives?
You shouldn't be forced to put composer.json anywhere else than the project root, but your reason to do so is barely explained. How did you configure your autoloading? You could simply add src/ to the autoloading path and move composer one level up - and subsequently change the path to vendor/autoload.php to be one directory level deeper than now.
Update
Based on the new information, you do split your project up during deployment, and the contents of the original src folder is copied/morphed/moved to a build folder.
I'd suggest to run composer install on the final build folder before pushing the files live. That means you need to copy the composer.json and most importantly composer.lock files into that build folder, and for reasons of symmetry, these files should reside inside src like you started, and then also copied.

Storing composer packages under development in the vendor directory, how to set up autoloader?

I am developing a package and I want to store it in the vendor directory before I publish it.
So, The path to say Basset's service provider once it is installed via composer is
/siteroot/vendor/jasonlewis/basset/src/Basset/BassetServiceProvider.php
which composer maps in it's autoloader fine, now If mine is at
/siteroot/vendor/hailwood/databaseconfigloader/src/DatabaseConfigLoader/DatabaseConfigLoaderServiceProvider.php
What do I need to add to the composer.json file to make it generate the autoload mapping correctly?
I can manually edit the autoload_namespaces.php file to add the mapping
'Hailwood\\DatabaseConfigLoader' => $vendorDir . '/hailwood/databaseconfigloader/src/'
and that works, but obviously gets overwritten when I do a composer update, I tried adding
"psr-0": {
"Hailwood\\DatabaseConfigLoader": "src/"
}
to the composer.json but that outputs 'Hailwood\\DatabaseConfigLoader' => $baseDir . '/src/', which doesn't work.
In state, you don't respect PSR-0. So you have two solutions :
Respect PSR-0
You must put your code in /siteroot/vendor/hailwood/databaseconfigloader/src/Hailwood/DatabaseConfigLoader/DatabaseConfigLoaderServiceProvider.php. After that, simply do :
"psr-0":
{
"Hailwood\\DatabaseConfigLoader": "vendor/hailwood/databaseconfigloader/src/"
}
Use classmap autoloading
Just try :
"classmap": ["vendor/hailwood/databaseconfigloader/src/"]

Categories