I'm running a one instance Apache setup with multiple virtual hosts that runs different versions of the same code base.
By this I mean that one virtual host can server one version of a class and another can server second version of the same class (same namespace, same name).
/file/path/host-a/MyClass.php
/file/path/host-b/MyClass.php
Sometimes I get an exception that shows me that one of the virtual hosts uses the "wrong" version of a class. E.g. on host b I get an exception with file path to script of /file/path/host-a/MyClass.php
I thought that the APC optcode cache used the file path, at least as a part of the key, but I'm fearing, that it only uses a qualified class name like:
My\Namespace\MyClass
Is that the case? Please point to any documentation on this subject if possible.
Answer
Though is was unable to find any documentation on the answer to this question php - APC opcode caching on different file versions explains that the APC optcode cache in fact does use the path of the file that defines the class to distinguis classes with the same name.
Debugging
After #hakra pointed out to me the behaviour of APC, I was able focus my efforts on the class loader. My class loader uses memcached as cache for storing the class paths. It turned out that the code for building cache keys were the cause of the problem - and not the APC which it seemed to be.
So should you be in a similar situation where your see that the incorrect "versions" of a class is loaded ensure that you class loader is working as expected. One obvious clue is of course the file path of the problem class.
Related
I am developing a web application using PhpStorm on OSx. I'm using Composer and have PSR-4 autoloading configured in composer.json. Everything is working fine on my development machine, but autoloading breaks when I upload to the production server which runs Linux.
After some troubleshooting it turns out that it's because OSx is using a case insensitive file system, while Linux is using a case sensitive one. And since my namespaces look like this
App\Service\AuthService
while my paths look like this
app/service/AuthService.php
the autoloader can't find the service folder on Linux, because it's looking for Service (with a capital S).
Okay, so I can fix this easily enough by just renaming all folders and class files to use the same cases as my namespaces. But in order to prevent any accidental case inconsistencies in the future, it would be nice if PhpStorm would warn me when I try to use
use App/Foo/Bar/HelloWorld;
while the actual file path is
app/foo/bar/HelloWorld.php
Is there such a setting I can use to have PhpStorm check this automatically, even when I'm developing on a machine with a case insensitive file system?
This equivalent Java question got an answer which uses a lower-level technique to reconfigure the IDE to treat the filesystem as case-sensitive.
Case sensitive files in IntelliJ Idea on Mac OSX
I have tried it and it does work, not just namespaces but any file that doesn't match in any way (e.g. includes, requires).
But it warns you on boot that you have said the FS is case-sensitive when it's not, and links to this article which has a few warnings/caveats about using this setting incorrectly.
PHPStorm: Help > Edit Custom Properties
Create the idea.properties file (if prompted)
Add idea.case.sensitive.fs=true
Restart the IDE
You may see:
Filesystem Case-Sensitivity Mismatch
The project seems to be located on a case-insensitive file system.
This does not match the IDE setting (controlled by property "idea.case.sensitive.fs")
More details. (show balloon)
https://confluence.jetbrains.com/display/IDEADEV/Filesystem+Case-Sensitivity+Mismatch
So I might try it as an option to do a sweep of errors, but perhaps not use it all the time.
PHPStorm provides the code inspection hint for it:
Go to the Preferences | Editor | Inspections
Choose section PHP | Code style
Turn on the option Case mismatch in method call or class usage.
It will highlight all the class names which are mistyped.
I'm using PHP 5.2 to make a website
I like to have explicit names for my classes
I also have a convention saying 'the path and name of a file' match the 'name of the class'
So a class called:
ABCSiteCore_Ctrlrs_DataTransfer_ImportMergeController
would sit in my svn working copy at:
C:\_my\websrv\ABCCoUkHosting2\webserve\my_library\vendor\ABCSiteCore-6-2\ABCSiteCore\Ctrlrs\DataTransfer\ImportMergeController.php
I find the naming convention gives me a better view of my code base, leading to better understanding and reducing the feeling of complexity.
Unfortunately there seems to be a max path length on my Windows XP PC. It seems to cause problems when I try to checkout Subversion files into my working copy.
If the path is too long, I can't check it out - the checkout fails.
So I find myself taking ages just to think of a name for a domain concept.
I might want to name a class "notification service" - but I end up calling it something like "NtfctnSrvce". It also cause problems when I try to create a specification class.
say, for example i'd love to have a spec class called with an explicit name,say:
$hasBeenNotifiedSpec = new ABCSiteCore_Model_MssgSys_Rules_Customers_HasCustomerBeenSentNotificationOfOnlineTransactionPaymentByEmail($notificationLog);
if($hasBeenNotifiedSpec->isSatisfiedBy($customer))
{
...do something
By using my file-to-class-name naming convention, I can simply use Windows Explorer to get a good idea of what the class does, its place /role in the Model/View/Controller pattern etc.
ABCSiteCore\
Model\
MssgSys\
Rules\
Customer\
HasCustomerBeenSentNotificationOfOnlineTransactionPaymentByEmail.php
Whenever i think of name for a domain concept, I've got into the habit of pasting the potential path length into a 'path length checker' to see if i can use it - its just a peice of pre-formatted text in my working-notes-wiki:
As you can see. Unfortunately that class name is getting close to the limits
C:\_my\websrv\ABCCoUkHosting2\webserve\my_library\vendor\ABCSiteCore-6-2\ABCSiteCore\Model\MssgSys\Rules\Customer\hasCustomerBeenSentNotificationOfOnlineTransactionPaymentByEmail.php
-------------------------------------------------------------------------------------------------------------------------------------------------------------------script path length danger zone------->|
----------------------------------------------------------------------------------------------------------------------------------------------------------------------max path length danger zone (inclusive .svn folder)------->|
C:\_my\websrv\ABCCoUkHosting2\webserve\my_library\vendor\ABCSiteCore-6-2\ABCSiteCore\Model\MssgSys\Rules\Customer\.svn\text-base\hasCustomerBeenSentNotificationOfOnlineTransactionPaymentByEmail.php.svn-base
Because of these path length restrictions, I tend to choose names for my entities that are not the best fit to the ubiquitous language of my domain model. This, can sometimes lead to misconceptions about how the system works, causes confusions and adds to the complexity - making development harder.
so :
How can I solve this issue?
is it solvable or is this just one one
those practical constraints that we
all just have to deal with?
is this just a PC thing? It might be time to switch to Mac or Linux.
Here's some abstract advice which may help you; yes switch operating systems, but not how you think - get virtualbox and load in a version of linux (ubuntu's nice and quick + well supported) then use that virtual os as your development os - this way you get the best of both worlds, and when you're finished working you simply close the virtual machine (saving it's state if you like) and have a nice clean pc to do what you want with.
The benefits are almost unlimited, for instance I have several virtual machines which I can load up whenever, some are testing setups, some mirror web server setups, I even have different editions of windows (such as an old XP with IE6) to test out browser bugs.
Surprisingly, I actually find my machine runs quicker using virtualbox; and please don't let the time to setup and run things worry you, as virtualbox is extremely quick, and you'll find your virtual machines load much faster than your primary os.
There are many other benefits which come with, but over all it's a very liberating experience :)
The cause is actually mentioned here: http://svn.haxx.se/users/archive-2005-02/1088.shtml
The long and short of it is that if you use absolute paths for your
operations, you get access to 32k of path length. Relative paths are
limited to ~255.
The Subversion libraries use relative paths. (I hate it, always have,
but that's a battle I've no time to wage.) That said, if you feed
Subversion an absolute path, well, paths relative to an absolute path
are still themselves absolute, so you should be okay. Also, if you
use TortoiseSVN on Windows, you should be okay, because it always
feeds Subversion absolute paths.
Pretty embarrassing for something that is called an OS, if you ask me. Workaround: Use Tortoise SVN. However I do not like Tortoise on the other hand since it's so slow.
As the question states, is this task safe for a production environment? I find the permissions rather permissive, the cache directory is the one i find particularly suspicious. Write and execution permission on a code directory is somewhat suspicious.
Cheers
Write: quite obviously needed to be able to cache data
Execute: in case of a directory, it means listing is allowed - i.e. to see if a cached version exists or not
the project:permissions task is safe to use in prod, it is as strict as it can be while still allowing normal usage.
Also keep in mind that the contents of your cache directory cannot be accessed from the outside.
It's fine for a dedicated production environment (like a VPS or dedicated server), but it's probably too permissive if you're on shared hosting - the defaults are world-writeable for the cache and upload folders, and you really only need to give access to the web server account (and possibly the user who can upload updates to the code).
You can make your own task that does the same thing but with tighter permissions:
copy the project:permissions task (lib/vendor/symfony/lib/task/project/sfProjectPermissionsTask.class.php) to your lib/task folder
rename the file and the class
change the declarations on lines 30 and 31 (e.g., 'project' and 'permissions-strict')
alter the permissions in the $this->chmod() method calls on lines 46-68. You may have to create a $this->chown() method too if you really want to lock things down.
(You could also extend the sfProjectPermissionsTask class, but since you'd be overriding just about everything, it doesn't really seem worthwhile)
I have a custom built application framework written in PHP which I have been tasked to optimize. This framework is a shared codebase which loads MVC "modules" to provide various functionality. Each module is a directory containing multiple PHP classes for controllers and models and PHP files for views.
The entire framework loads for almost all requests, including images and stylesheets. This is because the modules are designed to be self contained packages, and they may contain images, stylesheets, javascripts or other static files within them. Because of this, there is overhead in serving what would normally be a very simple request because the system has to load all the modules just to determine what modules are available from which to pull static files.
The general process for handling any given URI is as follows:
All base system classes are included
A global exception handler and some global variables are set
A system-wide configuration file is read. (This is a file filled with PHP statements to set config variables)
A connection to the database is made
The modules folder is scanned via opendir() and each module is verified to be valid and free of syntax errors, and then included.
A second configuration file is loaded which sets up configuration for the modules
A new instance of each module is created (calling it's __construct() method and possibly creating other database connections, performing individual startup routines, etc)
The URI is examined and passed off to the appropriate module(s)
Steps 1 - 7 will almost always be exactly the same. They will always perform the exact same operations unless new modules are installed or the configuration file is changed. My question is, what could be done to optimize the process? Ideally, I'd like some sort of way of handling multiple requests, similar to the way KeepAlive requests work. All the overhead of initializing all modules seems like a waste just to readfile() a single image or css file, just to have that same overhead again to serve another request.
Is there any way to reduce the overhead of a framework like this? (I don't even know if anyone can help me without studying all the code, this may be a hopeless question)
It's generally a bad idea to tie up a dynamic web server thread serving static content. Apache, IIS, Nginx, et. al. already do everything you need to serve up these files. If each static asset is located somewhere within the public docroot and has a unique URL, you shouldn't need to worry about PHP being involved in loading them.
Furthermore, if you can ensure that your cache-related headers (ETag, Last-Modified, etc.) are being generated correctly, and each client should only request each file once. Free caching == win!
Is there a reason all of the modules need to be loaded for every request? Why not allow controllers to specify which modules they require to be loaded, and only load those which are requested?
Why not move step 8 before step 5? Examine the URL first, then load modules based on the results.
Another one:
each module is verified to be valid and free of syntax errors, and then included.
Are you really syntax checking files before including() them? If so, why is this necessary?
I am running Symfony (1.2.9) with PHP Version 5.2.11 on Windows XP.
I have APC installed (Version 3.0.19)
I can run PHP script to prove that apc is working correctly (works). However, when I try to use APC calls in a symfony action, I get this error (in the apache error.log file):
[apc-error] Cannot redeclare class sfconfig
Which promptly crashes Apache.
I tried using the Symfony sfAPCCache wrapper, and then directly calling the apc_* functions - the result is the same. Does anyone know why this is happening ?
Checkout these threads:
http://pecl.php.net/bugs/bug.php?id=16860
http://old.nabble.com/APC-under-WinXP-crashes-td25872662.html
Today this error happened to me, too, and I became aware of why it can happen (among possible other reasons).
APC correctly identifies every class by a fully qualified name, which includes the classes namespace. Unfortunately you can end up referring to the same class with various names.
For example:
I had a wrong "use" statement in my code, importing a non-namespaced class as if it had been inside a namespace.
The class, say "MyClass" was in namespace "\", meaning that its correct and fully qualified name was "\MyClass".
At some point the class was referred to by its unqualified name "MyClass", and got autoloaded. In another file I (wrongly) referred to the class with a namespace prefix in a use statement, say "use \SomeNamespace\MyClass;". Consequently the class was (again) passed to my global __autoload() method, but with a different name. To make it worse, the autoload method was smart enough to find the class anyway.
Instantly, my script stopped working and all that happened was APC writing "[apc-error] Cannot redeclare class ..." into the Apache Web Server error.log. My pages were no longer available.
This is not an APC bug whatsoever, but simply correct behaviour.
In my case it helped to temporarily disable APC (so that my script would be run regardless of the conflict), and hook an echo statement into my __autoload function producing a list of the parameters passed. The class loaded with a wrong name would show up quickly, and I could fix it and reenable APC.
Hope this helps someone.
Ive had this error before unrelated to APC and it always helped to not only run the cache:clear but also to check and make sure all files were deleted from the cache dir.
I was living the same situation on my development windows
system with php 5.2.11 and several apc versions. Same
situation as described, with stat=0 everything works, but
when I set stat=1, apache crashes with error "cannot
redeclare class [some class]". The code is working on a
different windows system, beside it is live on a heavily
loaded linux production server for months. I'm %100 sure
there is no bug related to apc. It started on my machine
after I reinstalled my OS.
I spent some time commenting out some class includes and
realized that it works with some include files but not with
specific ones. I checked my code there is no noticeable
difference on the class differences.
Then I saved all of my include files with adding some
additional whitespaces with Zend Studio's editor. It looks
stupid I know but it works!!! I'm working on the project
with several people and using svn and everybody uses
different text editors like notepad++, editplus etc...
However I couldn't reproduce the error by trying save the
file with some different editors with different configs like
ansi, utf8 with/without byte-mark ordering etc. But I'm sure
my problem is something related to file format (encoding,
pc/unix mode). I'd like to reproduce the error and want to
give more detailed info but I tried my solution on another
project with same problem, it works either.
I hope I could give another perspective to the issue.
What solved this for me was making sure my requires had the same path.
For example, the error I got was:
[apc-error] Cannot redeclare class someClass
In file A I had the following:
require_once '/path/to/someClass.php';
In file B which resides in the same directory as someClass.php I had the following:
require_once 'someClass.php';
I believe that APC caching didn't understand they were the same file because the path was specified for one and not the other.