apc_exist() does not exist? - php

I'm having some hard time getting PHP APC to work. Here's my test code:
<form>
<input type="text" name="apc">
<input type="submit">
</form>
<?php
apc_store('foo','FOO');
if (isset($_GET['apc'])) {
apc_store($_GET['apc'],$_GET['apc']);
}
?>
<pre>CACHE INFO (USER): <?php print_r(apc_cache_info("user",false)); ?></pre>
<pre>CACHE INFO: <?php print_r(apc_cache_info()); ?></pre>
<pre>FOO: <?php print_r(apc_fetch("foo")); ?></pre>
<pre>BAR: <?php print_r(apc_fetch("bar")); ?></pre>
<pre><?php if (apc_exists("bar")) { ?>bar exists!<?php } else { ?>bar does not exist!<?php } ?></pre>
<?php apc_clear_cache(); ?>
In short: you fill the form and the inserted value gets stored in APC. The key "foo" is always stored. You can try storing "bar" to see apc_fetch() working with a newly added key.
What works OK:
apc_store()
apc_fetch()
What does not:
apc_cache_info() (regardless of which parametres I pass to the function) always prints an empty array, despite apc_fetch() retrieving data successfully
apc_clear_cache() never clears the cache ("bar" is always displayed once input). This is true both if I provide a "user" parametre or leave the function with no parametres.
calling apc_exists() yields a fatal error: call to undefined function apc_exists()
In case it's helpful: I'm running Zend Server CE 5.6.0 (fresh install, finished half an hour ago), with PHP 5.3.9. Same happened with a more antique version of Zend Server CE yesterday (running PHP 5.3.5). I do not know which version of APC ships with Zend Server, phpinfo() only shows APC is enabled. I am on a Windows machine (Windows 7 Professional, 32 bit).
So. What's wrong here? Issues with my code? Maybe Zend Server ships with an older version of APC that just is buggy and/or does not support the functions I'm trying to use? Any clues?
[EDIT]
Inspired by clues provided by #Hannes, I modified the code, adding:
<?php
if (!function_exists('apc_exists') {
function apc_exists($key) { return (boolean)apc_fetch($key); }
}
?>
Since no error is raised, the code passes to the next line and the cache is cleared OK. This must have been why it wasn't cleared in the first place.
Still, apc_cache_info() doesn't return anything...

apc_exists is available for PECL apc >= 3.1.4 http://www.php.net/manual/en/function.apc-exists.php so your APC Version is probbaly lower, but its basically just a boolean wraper anyhow, a simple function shoud basically do the same:
function user_apc_exists($key){ return (bool) apc_fetch($key); }
in both cases your didint provide information for which cache to use, your probaby want user:
apc_clear_cache('user');
apc_cache_info('user);
http://www.php.net/manual/en/function.apc-clear-cache.php
http://www.php.net/manual/en/function.apc-cache-info.php

I ran across the same problem and after some debugging found out that the function in Hannes' answer works unless the stored data is a boolean false or an empty array.
This works also in those cases:
if (!function_exists('apc_exists')) {
function apc_exists($key) {
$success = false;
apc_fetch($key, $success);
return $success;
}
}

Related

How to make new version updating safe in PHP OpCache?

My php project is now working on Apache with mod_php. I want to open OpCache to accelerate my code. But I'm worry about if it's safe to update the code.
The validate_timestamps should be 0. Because the code may expire when you update new version, and this can make the code of new version call the code of old version.
But even if I set validate_timestamps=0, this can also happen. When I update the code file, one of the code file that hasn't been cached is called. And thus this code file is in new version while the caller is in old version. Maybe I can load all the code files into cache before the server start?
If I find a way to make sure all the files in the project dir are loaded into cache before the Apache start to serve requests, I can update new version code first, and then clear all the OpCache. But does it have an impact on those working requests? Will they run an old logic and then be switch into a new one?
Besides, how to clear all the OpCache in an atom time? If it takes time to clear all the OpCache, the problem is still there, right?
Can anyone help me? Thank you very much!
Let me show an example.
I have two files on my directory, and the Apache's working directory is also there.
The entry file is index.php.
<?php
echo "verson 1: index";
// do some work
sleep(1);
// not all APIs will call this library
// I just use rand to represent a probability
if (rand(0,100) == 1) {
require_once BASEPATH.'lib.php';
t = new Tester();
t->func1();
}
And the other php file is lib.php.
<?php
echo "---- version 1: lib";
class Tester {
function __construct() {
echo "---- new Tester in lib.php";
}
public function func1() {
echo "---- Tester.func1()";
}
}
Now I'm going to upload my new version code.
In the new version, I declare a new function func2() in Tester and delete the old function func1(). I call it in the index.php.
index.php
<?php
echo "version 2: index";
// do some work
sleep(1);
// not all APIs will call this library
// I just use rand to represent a probability
if (rand(0,100) == 1) {
require_once BASEPATH.'lib.php';
t = new Tester();
t->func2();
}
lib.php
<?php
echo "---- version 2: lib";
class Tester {
function __construct() {
echo "---- new Tester in lib.php";
}
public function func2() {
echo "---- Tester.func2()";
}
}
I close the OpCache. I upload the index.php first and then the other one lib.php. At the moment between I finish to upload the index.php and begin to upload lib.php, a request is running into the "rand case". Then I will get an error about "func2() not defined", because the lib.php is still the old one at that time.
If I open the OpCache, it's the same if I don't set validate_timestamps to 0.
After I set validate_timestamps to 0, the opcode will not expire. So I must call opcache_reset manually after I finish to upload index.php and lib.php. At that moment, a request also runs into the "rand case". If the opcache_reset operation takes a period of time, and it doesn't block the request running, the error "func2() not defined" may also occur.
How to make all the requests safe when I upgrade my code version?

#date_default_timezone_get() silently crashes

I have the following test code:
<html>
<body>
<p>
Hi
</p>
<?php
if (function_exists('date_default_timezone_get')) {
echo "J";
$timezone = #date_default_timezone_get();
echo "K";
date_default_timezone_set($timezone);
echo "L";
}
phpinfo();
?>
</body>
</html>
When I retrieve it through my apparently working apache I get just:
<html>
<body>
<p>
Hi
</p>
J
If I comment out the '$timezone = #date_default_timezone_get();' then I get a response with an error about '$timezone' not being defined and then the standard phpinfo() output.
All of the debugging options I've found thus far don't show me anything of interest in any log.
Running the script with php on the command line it gives no error either.
FYI: This is me attempting to figure out why my websvn suddenly stopped working, I've narrowed down the failure to this line and it fails in the sample code, so I'm feeling reasonably good about this other than why it just wont work.
Why are you keeping the # before the function call? It suppresses the error output which may be of help.
Also, what PHP version are you using? DateTime functions are only enabled by default since 5.2.0.
I wouldn't also exclude the possibility that even though date_default_timezone_get() function exists, it is not a standard one that comes with PHP, but something custom-made instead.
After commenting out the call entirely in websvn I got a new error from another line:
Timezone database is corrupt - this should never happen!
This error led me to investigate what was wrong with my timezone info and apparently all of files in /usr/share/zoneinfo/ had 640 permissions, changing them to 644 and the errors have gone.

is_readable() only returns true if called at least once before session_start

There is something strange on one of my PHP servers. Other servers show different behaviour. But I don't think this is caused by an environment setting.
I'm starting to believe this is a bug. Has anyone heard of this?
is_readable() will only return true if you call it at least once before you start the session.
If you start the session first, all is_readable() calls return false. Though you can still read the file with readfile() anyway.
<?php
// do session_start() to here and you will get BadBad
error_reporting(E_ALL);
ini_set('display_errors',1);
ini_set('display_startup_errors',1);
ob_start();
// or do session_start() here and you will also get BadBad
echo is_readable("foo.bar") ? "Good" : "Bad";
// But do session_start() here and you get GoodGood
echo is_readable("foo.bar") ? "Good" : "Bad";
// or even do it here and you will still get GoodGood
echo #++$_SESSION['counter']; // incrementing number always follow GoodGood or BadBad
readfile("foo.bar"); // the contents also always follow GoodGood or BadBad
?>
The incrementing number always shows, so sessions are working fine.
Also the file contents always shows, so the file is readable.
I'm running 32 bit PHP Version 5.3.26 on Windows Server 2012 64 bit with IIS 7.5.
What could it be?

PHP Trait method works only on first load

I'm using MAMP with PHP 5.4.10 and I have a problem with the following MWE:
<?php
trait T {
public function hello() { echo 'hello'; }
}
class A {
use T;
}
$a = new A();
$a->hello();
?>
The page shows 'hello' on the first load. But then, when I hit refresh, I get an Error 500.
If I modify the file (just by adding an empty line somewhere for instance) and refresh again, 'hello' shows up again. Hit refresh again, and the Error 500 is back.
Any clue where this might be coming from?
Update:
This shows up in the PHP errors log (nothing in the Apache errors log): PHP Fatal error: Call to undefined method A::0?
()
(the 0 doesn't always have the same name when I repeat the operation).
Xcache might be the problem here, try turning caching off (or at least xcache) and try it again
I had the same problem, and thanks to the #Leon Weemen i focused on the XCache. I found this bug (which is fixed in XCache 3.0.1) to be exactly what causes the problem (my version of XCache was 2.0.0). They suggest you to set in your php.ini the following values to solve the problem;
xcache.mmap_path = "/tmp/xcache"
xcache.readonly_protection = on
However, this workaround does not solve the problem for me. The only way I was able to disable the XCache was by using the ini_set() PHP method. The following snippet at the very begginning of my application solves the problem and is ready to use XCache as soon as it is updated:
try{
$xCache = new ReflectionExtension('xcache');
if(version_compare($xCache->getVersion(), '3.0.1', '<')){
ini_set('xcache.cacher', 0);
}
} catch(ReflectionException $e){
// xCache not installed - everything should work fine
}

PHP voting code works on 5.2.5 but not on 5.2.11 anymore

Ok, so a little while back I had some help writing some PHP voting code, it worked just fine after I upgraded my server to use the latest version of PHP. However now I have switched servers, and the PHP isn't as up to date as the other one. Anyways here's my code:
<?php
if(!file_exists('vote/1u.txt')){
file_put_contents('vote/1u.txt', '+1');
}
if($_GET['click'] == 'up1'){
file_put_contents('vote/1u.txt', ((int) file_get_contents('vote/1u.txt')) + 1);
header('Location: ' . $_SERVER['SCRIPT_NAME']);
die;
}
?>
Execute and display:
<img src="images/thumbsup.jpg" width="40px"border="0"> <br>Votes: <?php echo file_get_contents('vote/up1.txt'); ?>
Now when on my other server (PHP version 5.2.5) this code worked great! However on my new server the PHP version is 5.2.11, and because of this the code won't work. My question is, is there any way to make this more compatible with an earlier version of PHP, or to write completely new code that will work just like this one? Or is there a way to tell my servers to use PHP 5.2.5+? I'm using cPanel X admin panel.
I have set the text file permissions to 777 and still nothing!
you are checking for variable "click" but executing the code only if it equals "up1".
But your link tells click to equals "yes" so that part of the code is never true, hence never executed.
Change your executor to this:
<img src="images/thumbsup.jpg" width="40px"border="0"> <br>Votes: <?php echo file_get_contents('counteru.txt'); ?>
But more logically, your processing code should be rationalized a bit to this:
if the link is clicked :
First, if the data file (lu.txt) does not exist, create it and write '+1' inside of it, else, add 1 to its existing value.
Then, redirects to the initial page.
if($_GET['click'] == 'up1'){
if(!file_exists('vote/1u.txt')){
file_put_contents('vote/1u.txt', '+1');
}else{
$content = file_get_contents('vote/1u.txt');
if(!$content){
die("Error! file_get_content failed !");
}
file_put_contents('vote/1u.txt', ((int)$content) + 1);
}
header('Location: ' . $_SERVER['SCRIPT_NAME']);
}
exit;
Not a bad idea to add a trim() around file_get_contents(). Or to check if $_GET['click'] isset() prior to checking if it's equal to 'up1'.
It's conventional to exit() instead of die() after a header redirect--well, from what I've seen at least.
Basically, during development, turn on error reporting and set your error flag to E_ALL to see everything, including warnings and notices--neither of which halt your code, but should still be known and addressed.
You might discover the reason your code produces different outcomes under different minor versions of PHP by turning on full error reporting.

Categories