1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
<?php
/**
* Copyright © 2013-2017 Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Update;
/**
* This class is used by Updater cron script to check if it can be run properly
*/
class CronReadinessCheck
{
/**
* Basename to Updater status file
*/
const CRON_JOB_STATUS_FILE = '.update_cronjob_status';
const UPDATE_CRON_LOG_FILE = 'var/log/update.log';
/**#@+
* Keys used in status file
*/
const KEY_READINESS_CHECKS = 'readiness_checks';
const KEY_FILE_PERMISSIONS_VERIFIED = 'file_permissions_verified';
const KEY_ERROR = 'error';
const KEY_CURRENT_TIMESTAMP = 'current_timestamp';
const KEY_LAST_TIMESTAMP = 'last_timestamp';
/**#@-*/
/**
* Setup cron job status file name
*/
const SETUP_CRON_JOB_STATUS_FILE = '.setup_cronjob_status';
/**#@+
* Keys from .setup_cronjob_status file
*/
const KEY_FILE_PATHS = 'file_paths';
const KEY_LIST = 'list';
/**#@-*/
/**
* Run Cron job readiness check
*
* @return bool
*/
public function runReadinessCheck()
{
$resultJsonRawData = ['readiness_checks' => []];
$success = true;
$permissionInfo = $this->checkPermissionsRecursively();
if ($permissionInfo->containsPaths())
{
$error = '';
$outputString = '';
if (!empty($permissionInfo->getNonWritablePaths())) {
$error .= '<br/>Found non-writable path(s):<br/>' .
implode('<br/>', $permissionInfo->getNonWritablePaths());
$outputString = 'Cron readiness check failure! Found non-writable paths:'
. PHP_EOL
. "\t"
. implode(PHP_EOL . "\t", $permissionInfo->getNonWritablePaths());
}
if (!empty($permissionInfo->getNonReadablePaths())) {
$error .= '<br/>Found non-readable path(s):<br/>' .
implode('<br/>', $permissionInfo->getNonReadablePaths());
$outputString .= PHP_EOL
. 'Cron readiness check failure! Found non-readable paths:'
. PHP_EOL
. "\t"
. implode(PHP_EOL . "\t", $permissionInfo->getNonReadablePaths());
}
$resultJsonRawData[self::KEY_READINESS_CHECKS][self::KEY_ERROR] = $error;
$resultJsonRawData[self::KEY_READINESS_CHECKS][self::KEY_FILE_PERMISSIONS_VERIFIED] = false;
$success = false;
} else {
$resultJsonRawData[self::KEY_READINESS_CHECKS][self::KEY_FILE_PERMISSIONS_VERIFIED] = true;
}
if (file_exists(MAGENTO_BP . '/var/' . self::CRON_JOB_STATUS_FILE)) {
$jsonData = json_decode(file_get_contents(MAGENTO_BP . '/var/' . self::CRON_JOB_STATUS_FILE), true);
if (isset($jsonData[self::KEY_CURRENT_TIMESTAMP])) {
$resultJsonRawData[self::KEY_LAST_TIMESTAMP] = $jsonData[self::KEY_CURRENT_TIMESTAMP];
}
}
$resultJsonRawData[self::KEY_CURRENT_TIMESTAMP] = time();
$resultJson = json_encode($resultJsonRawData, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
file_put_contents(MAGENTO_BP . '/var/' . self::CRON_JOB_STATUS_FILE, $resultJson);
// If non-accessible paths are found, log an 'error' entry for the same in update.log
if ( !$success && !empty($outputString) ) {
$updateLoggerFactory = new UpdateLoggerFactory();
$logger = $updateLoggerFactory->create();
$logger->log(\Psr\Log\LogLevel::ERROR, $outputString);
}
return $success;
}
/**
* Check file permissions recursively
*
* @return PermissionInfo
*/
private function checkPermissionsRecursively()
{
// For backward compatibility, initialize the list wth magento root directory.
$dirAndFileList[] = '';
// Get the list of magento specific directories and files
$setupCronJobStatusFilePath = MAGENTO_BP . '/var/' . self::SETUP_CRON_JOB_STATUS_FILE;
if (is_readable($setupCronJobStatusFilePath)) {
$fileContents = json_decode(file_get_contents($setupCronJobStatusFilePath), true);
if (isset($fileContents[self::KEY_FILE_PATHS][self::KEY_LIST])) {
$dirAndFileList = $fileContents[self::KEY_FILE_PATHS][self::KEY_LIST];
}
}
$nonWritablePaths = [];
$nonReadablePaths = [];
foreach ($dirAndFileList as $path) {
$path = MAGENTO_BP . '/' . $path;
if (is_dir($path)) {
try {
$filesystemIterator = new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($path),
\RecursiveIteratorIterator::SELF_FIRST
);
$filesystemIterator = new ExcludeFilter(
$filesystemIterator,
[
MAGENTO_BP . '/update',
MAGENTO_BP . '/var/session',
'.git',
'.idea'
]
);
foreach ($filesystemIterator as $item) {
$path = $item->__toString();
if (!is_writable($path)) {
$nonWritablePaths[] = $path;
}
}
} catch (\UnexpectedValueException $e) {
$nonReadablePaths[] = $path;
}
} else {
if (!is_writable($path)) {
$nonWritablePaths[] = $path;
}
}
}
return new PermissionInfo($nonWritablePaths, $nonReadablePaths);
}
}