Skip to content

Commit b0fd657

Browse files
JanTvrdikdg
authored andcommitted
ContainerLoader, ContainerFactory: fixed thread-safety issues
1 parent 59c576e commit b0fd657

File tree

2 files changed

+54
-51
lines changed

2 files changed

+54
-51
lines changed

src/DI/ContainerFactory.php

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -110,44 +110,44 @@ private function loadClass()
110110
{
111111
$key = md5(serialize(array($this->config, $this->configFiles, $this->class, $this->parentClass)));
112112
$file = "$this->tempDirectory/$key.php";
113-
114-
if (!$this->autoRebuild && (@include $file) !== FALSE) { // @ - file may not exist
113+
if (!$this->isExpired($file) && (@include $file) !== FALSE) {
115114
return;
116115
}
117116

118117
$handle = fopen("$file.lock", 'c+');
119-
if (!$handle) {
120-
throw new Nette\IOException("Unable to open or create file '$file.lock'.");
118+
if (!$handle || !flock($handle, LOCK_EX)) {
119+
throw new Nette\IOException("Unable to acquire exclusive lock on '$file.lock'.");
121120
}
122121

123-
if ($this->autoRebuild) {
124-
flock($handle, LOCK_SH);
125-
foreach ((array) @unserialize(file_get_contents("$file.meta")) as $f => $time) { // @ - file may not exist
126-
if (@filemtime($f) !== $time) { // @ - stat may fail
127-
@unlink($file); // @ - file may not exist
128-
break;
122+
if (!is_file($file) || $this->isExpired($file)) {
123+
$this->dependencies = array();
124+
$toWrite[$file] = $this->generateCode();
125+
$files = $this->dependencies ? array_combine($this->dependencies, $this->dependencies) : array();
126+
$toWrite["$file.meta"] = serialize(@array_map('filemtime', $files)); // @ - file may not exist
127+
128+
foreach ($toWrite as $name => $content) {
129+
if (file_put_contents("$name.tmp", $content) !== strlen($content) || !rename("$name.tmp", $name)) {
130+
@unlink("$name.tmp"); // @ - file may not exist
131+
throw new Nette\IOException("Unable to create file '$name'.");
129132
}
130133
}
131134
}
132135

133-
if (!is_file($file)) {
134-
flock($handle, LOCK_EX);
135-
if (!is_file($file)) {
136-
$this->dependencies = array();
137-
$code = $this->generateCode();
138-
if (file_put_contents("$file.tmp", $code) !== strlen($code) || !rename("$file.tmp", $file)) {
139-
@unlink("$file.tmp"); // @ - file may not be created
140-
throw new Nette\IOException("Unable to create file '$file'.");
141-
}
142-
$tmp = array();
143-
foreach ($this->dependencies as $f) {
144-
$tmp[$f] = @filemtime($f); // @ - stat may fail
145-
}
146-
file_put_contents("$file.meta", serialize($tmp));
147-
}
136+
if ((@include $file) === FALSE) { // @ - error escalated to exception
137+
throw new Nette\IOException("Unable to include '$file'.");
148138
}
139+
flock($handle, LOCK_UN);
140+
}
141+
149142

150-
require $file;
143+
private function isExpired($file)
144+
{
145+
if ($this->autoRebuild) {
146+
$meta = @unserialize(file_get_contents("$file.meta")); // @ - files may not exist
147+
$files = $meta ? array_combine($tmp = array_keys($meta), $tmp) : array();
148+
return $meta !== @array_map('filemtime', $files); // @ - files may not exist
149+
}
150+
return FALSE;
151151
}
152152

153153

src/DI/ContainerLoader.php

Lines changed: 28 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -61,46 +61,49 @@ public function getClassName($key)
6161
private function loadFile($class, $generator)
6262
{
6363
$file = "$this->tempDirectory/$class.php";
64-
if (!$this->autoRebuild && (@include $file) !== FALSE) { // @ - file may not exist
64+
if (!$this->isExpired($file) && (@include $file) !== FALSE) {
6565
return;
6666
}
6767

6868
if (!is_dir($this->tempDirectory)) {
6969
@mkdir($this->tempDirectory); // @ - directory may already exist
7070
}
71+
7172
$handle = fopen("$file.lock", 'c+');
72-
if (!$handle) {
73-
throw new Nette\IOException("Unable to open or create file '$file.lock'.");
73+
if (!$handle || !flock($handle, LOCK_EX)) {
74+
throw new Nette\IOException("Unable to acquire exclusive lock on '$file.lock'.");
7475
}
7576

76-
if ($this->autoRebuild) {
77-
flock($handle, LOCK_SH);
78-
foreach ((array) @unserialize(file_get_contents("$file.meta")) as $f => $time) { // @ - file may not exist
79-
if (@filemtime($f) !== $time) { // @ - stat may fail
80-
@unlink($file); // @ - file may not exist
81-
break;
77+
if (!is_file($file) || $this->isExpired($file)) {
78+
list($code, $files) = call_user_func($generator, $class);
79+
80+
$files = $files ? array_combine($files, $files) : array();
81+
$toWrite["$file.meta"] = serialize(@array_map('filemtime', $files)); // @ - file may not exist
82+
$toWrite[$file] = "<?php\n$code";
83+
84+
foreach ($toWrite as $name => $content) {
85+
if (file_put_contents("$name.tmp", $content) !== strlen($content) || !rename("$name.tmp", $name)) {
86+
@unlink("$name.tmp"); // @ - file may not exist
87+
throw new Nette\IOException("Unable to create file '$name'.");
8288
}
8389
}
8490
}
8591

86-
if (!is_file($file)) {
87-
flock($handle, LOCK_EX);
88-
if (!is_file($file)) {
89-
list($code, $dependencies) = call_user_func($generator, $class);
90-
$code = "<?php\n" . $code;
91-
if (file_put_contents("$file.tmp", $code) !== strlen($code) || !rename("$file.tmp", $file)) {
92-
@unlink("$file.tmp"); // @ - file may not be created
93-
throw new Nette\IOException("Unable to create file '$file'.");
94-
}
95-
$tmp = array();
96-
foreach ((array) $dependencies as $f) {
97-
$tmp[$f] = @filemtime($f); // @ - stat may fail
98-
}
99-
file_put_contents("$file.meta", serialize($tmp));
100-
}
92+
if ((@include $file) === FALSE) { // @ - error escalated to exception
93+
throw new Nette\IOException("Unable to include '$file'.");
10194
}
95+
flock($handle, LOCK_UN);
96+
}
97+
10298

103-
require $file;
99+
private function isExpired($file)
100+
{
101+
if ($this->autoRebuild) {
102+
$meta = @unserialize(file_get_contents("$file.meta")); // @ - files may not exist
103+
$files = $meta ? array_combine($tmp = array_keys($meta), $tmp) : array();
104+
return $meta !== @array_map('filemtime', $files); // @ - files may not exist
105+
}
106+
return FALSE;
104107
}
105108

106109
}

0 commit comments

Comments
 (0)