Skip to content

Commit 53ae2ce

Browse files
authored
Merge pull request #215 from namithj/#187
2 parents 0cfc765 + 500676e commit 53ae2ce

11 files changed

+684
-197
lines changed

assets/js/aspire-update.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ class ViewLog {
9797
jQuery.ajax(parameters)
9898
.done(function (response) {
9999
if ((true == response.success) && ('' != response.data.content)) {
100-
let lines = response.data.content.split(aspireupdate.line_ending);
100+
let lines = response.data.content;
101101
jQuery.each(lines, function (index, line) {
102102
jQuery('<div>')
103103
.append(

includes/class-debug.php

+40-78
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,13 @@ class Debug {
1919
*/
2020
private static $log_file = 'debug-aspire-update.log';
2121

22+
/**
23+
* The filesystem.
24+
*
25+
* @var Filesystem_Direct
26+
*/
27+
private static $filesystem;
28+
2229
/**
2330
* Get the Log file path.
2431
*
@@ -31,79 +38,41 @@ private static function get_file_path() {
3138
/**
3239
* Initializes the WordPress Filesystem.
3340
*
34-
* @return WP_Filesystem_Base|false The filesystem object or false on failure.
41+
* @return Filesystem_Direct The filesystem object.
3542
*/
3643
private static function init_filesystem() {
37-
global $wp_filesystem;
38-
39-
if ( ! $wp_filesystem ) {
44+
if ( ! self::$filesystem instanceof Filesystem_Direct ) {
4045
require_once ABSPATH . 'wp-admin/includes/file.php';
46+
require_once ABSPATH . 'wp-admin/includes/class-wp-filesystem-base.php';
47+
require_once ABSPATH . 'wp-admin/includes/class-wp-filesystem-direct.php';
4148
WP_Filesystem();
49+
self::$filesystem = new Filesystem_Direct( false );
4250
}
43-
44-
return $wp_filesystem;
45-
}
46-
47-
/**
48-
* Checks the filesystem status and logs error to debug log.
49-
*
50-
* @param WP_Filesystem_Base $wp_filesystem The filesystem object.
51-
*
52-
* @return boolean true on success and false on failure.
53-
*/
54-
private static function verify_filesystem( $wp_filesystem ) {
55-
if ( ! $wp_filesystem ) {
56-
if (
57-
defined( 'WP_DEBUG' ) &&
58-
( true === WP_DEBUG ) &&
59-
defined( 'WP_DEBUG_LOG' ) &&
60-
( true === WP_DEBUG_LOG )
61-
) {
62-
// phpcs:disable WordPress.PHP.DevelopmentFunctions
63-
/**
64-
* Log error in file write fails only if debug is set to true. This is a valid use case.
65-
*/
66-
error_log( 'AspireUpdate - Could not open or write to the file system. Check file system permissions to debug log directory.' ); // @codeCoverageIgnore
67-
// phpcs:enable
68-
}
69-
return false;
70-
}
71-
return true;
51+
return self::$filesystem;
7252
}
7353

7454
/**
7555
* Get the content of the log file truncated upto N number of lines.
7656
*
7757
* @param integer $limit Max no of lines to return. Defaults to a 1000 lines.
7858
*
79-
* @return string|WP_Error The File content truncate upto the number of lines set in the limit parameter.
59+
* @return array|WP_Error An array of lines in the file, limited to $limit, or a WP_Error object on failure.
8060
*/
8161
public static function read( $limit = 1000 ) {
8262
$wp_filesystem = self::init_filesystem();
8363
$file_path = self::get_file_path();
84-
if ( ! self::verify_filesystem( $wp_filesystem ) || ! $wp_filesystem->exists( $file_path ) || ! $wp_filesystem->is_readable( $file_path ) ) {
64+
65+
if ( ! $wp_filesystem->exists( $file_path ) || ! $wp_filesystem->is_readable( $file_path ) ) {
8566
return new \WP_Error( 'not_readable', __( 'Error: Unable to read the log file.', 'aspireupdate' ) );
8667
}
8768

88-
$file_content = $wp_filesystem->get_contents_array( $file_path );
89-
$content = '';
90-
$index = 0;
91-
foreach ( $file_content as $file_content_lines ) {
92-
if ( ( $index < $limit ) ) {
93-
$content .= $file_content_lines . PHP_EOL;
94-
++$index;
95-
}
96-
}
97-
if ( '' === trim( $content ) ) {
98-
$content = esc_html__( '*****Log file is empty.*****', 'aspireupdate' );
99-
} elseif ( $limit < count( $file_content ) ) {
100-
$content .= PHP_EOL . sprintf(
101-
/* translators: 1: The number of lines at which the content was truncated. */
102-
esc_html__( '*****Log truncated at %s lines.*****', 'aspireupdate' ),
103-
$limit
104-
);
69+
$file_content = $wp_filesystem->get_contents_array( $file_path, $limit, true );
70+
71+
if ( ( false === $file_content ) || ( 0 === count( array_filter( $file_content ) ) ) ) {
72+
$file_content = [ esc_html__( '*****Log file is empty.*****', 'aspireupdate' ) ];
10573
}
106-
return $content;
74+
75+
return $file_content;
10776
}
10877

10978
/**
@@ -114,7 +83,8 @@ public static function read( $limit = 1000 ) {
11483
public static function clear() {
11584
$wp_filesystem = self::init_filesystem();
11685
$file_path = self::get_file_path();
117-
if ( ! self::verify_filesystem( $wp_filesystem ) || ! $wp_filesystem->exists( $file_path ) || ! $wp_filesystem->is_writable( $file_path ) ) {
86+
87+
if ( ! $wp_filesystem->exists( $file_path ) || ! $wp_filesystem->is_writable( $file_path ) ) {
11888
return new \WP_Error( 'not_accessible', __( 'Error: Unable to access the log file.', 'aspireupdate' ) );
11989
}
12090

@@ -133,30 +103,22 @@ public static function clear() {
133103
* @param string $type The log level ('string', 'request', 'response').
134104
*/
135105
public static function log( $message, $type = 'string' ) {
136-
$wp_filesystem = self::init_filesystem();
137-
if ( self::verify_filesystem( $wp_filesystem ) ) {
138-
$timestamp = gmdate( 'Y-m-d H:i:s' );
139-
$formatted_message = sprintf(
140-
'[%s] [%s]: %s',
141-
$timestamp,
142-
strtoupper( $type ),
143-
self::format_message( $message )
144-
) . PHP_EOL;
145-
146-
$file_path = self::get_file_path();
147-
148-
$content = '';
149-
if ( $wp_filesystem->exists( $file_path ) ) {
150-
if ( $wp_filesystem->is_readable( $file_path ) ) {
151-
$content = $wp_filesystem->get_contents( $file_path );
152-
}
153-
}
154-
$wp_filesystem->put_contents(
155-
$file_path,
156-
$formatted_message . $content,
157-
FS_CHMOD_FILE
158-
);
159-
}
106+
$wp_filesystem = self::init_filesystem();
107+
$timestamp = gmdate( 'Y-m-d H:i:s' );
108+
$formatted_message = sprintf(
109+
'[%s] [%s]: %s',
110+
$timestamp,
111+
strtoupper( $type ),
112+
self::format_message( $message )
113+
) . PHP_EOL;
114+
115+
$file_path = self::get_file_path();
116+
$wp_filesystem->put_contents(
117+
$file_path,
118+
$formatted_message,
119+
FS_CHMOD_FILE,
120+
'a'
121+
);
160122
}
161123

162124
/**

includes/class-filesystem-direct.php

+104
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
<?php
2+
/**
3+
* The Class for WordPress Direct Filesystem with optimized read and write routines.
4+
*
5+
* @package aspire-update
6+
*/
7+
8+
namespace AspireUpdate;
9+
10+
/**
11+
* The Class for WordPress Direct Filesystem with optimized read and write routines.
12+
*/
13+
class Filesystem_Direct extends \WP_Filesystem_Direct {
14+
15+
/**
16+
* Reads entire file into an array with options for limiting the number of lines and direction from the the lines are counted.
17+
*
18+
* @param string $file Path to the file.
19+
* @param int $number_of_lines The number of lines to read. Default is -1 (read all lines).
20+
* @param bool $count_bottom_to_top Count the lines from the bottom up. Default is false (count from top to bottom).
21+
*
22+
* @return array|false File contents in an array on success, false on failure.
23+
*/
24+
public function get_contents_array( $file, $number_of_lines = -1, $count_bottom_to_top = false ) {
25+
if ( ! $this->exists( $file ) ) {
26+
return false;
27+
}
28+
29+
if ( -1 === $number_of_lines ) {
30+
return @file( $file );
31+
}
32+
33+
$handle = @fopen( $file, 'r' );
34+
if ( ! $handle ) {
35+
return false;
36+
}
37+
38+
$lines = [];
39+
$line_count = 0;
40+
41+
// phpcs:disable Generic.CodeAnalysis.AssignmentInCondition.FoundInWhileCondition
42+
/**
43+
* This is a valid and intentional use.
44+
*/
45+
while ( ( $line = fgets( $handle ) ) !== false ) {
46+
$lines[] = trim( $line );
47+
++$line_count;
48+
49+
if ( $count_bottom_to_top ) {
50+
if ( $number_of_lines > 0 && $line_count > $number_of_lines ) {
51+
array_shift( $lines );
52+
}
53+
} elseif ( $number_of_lines > 0 && $line_count >= $number_of_lines ) {
54+
break;
55+
}
56+
}
57+
// phpcs:enable
58+
59+
fclose( $handle );
60+
61+
return $lines;
62+
}
63+
64+
/**
65+
* Write contents to a file with additional modes.
66+
*
67+
* @param string $file The path to the file.
68+
* @param string $contents The content to write.
69+
* @param int|false $mode Optional. The file permissions as octal number, usually 0644.
70+
* Default false.
71+
* @param string $write_mode The write mode:
72+
* 'w' - Overwrite the file (default).
73+
* 'a' - Append to the file.
74+
* 'x' - Create a new file and write, fail if the file exists.
75+
* 'c' - Open the file for writing, but do not truncate.
76+
* @return bool True on success, false on failure.
77+
*/
78+
public function put_contents( $file, $contents, $mode = false, $write_mode = 'w' ) {
79+
$valid_write_modes = [ 'w', 'a', 'x', 'c' ];
80+
if ( ! in_array( $write_mode, $valid_write_modes, true ) ) {
81+
return false;
82+
}
83+
84+
$handle = @fopen( $file, $write_mode );
85+
if ( ! $handle ) {
86+
return false;
87+
}
88+
89+
mbstring_binary_safe_encoding();
90+
$data_length = strlen( $contents );
91+
$bytes_written = fwrite( $handle, $contents );
92+
reset_mbstring_encoding();
93+
94+
fclose( $handle );
95+
96+
if ( $data_length !== $bytes_written ) {
97+
return false;
98+
}
99+
100+
$this->chmod( $file, $mode );
101+
102+
return true;
103+
}
104+
}

phpcs.xml.dist

+23
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,23 @@
5959
<!-- Enforce short syntax arrays. -->
6060
<rule ref="Generic.Arrays.DisallowLongArraySyntax"/>
6161

62+
<!-- Exclude custom Filesystem API implementations from certain sniffs. -->
63+
<rule ref="WordPress.WP.AlternativeFunctions.file_system_operations_fopen">
64+
<exclude-pattern>includes/class-filesystem-direct\.php</exclude-pattern>
65+
</rule>
66+
67+
<rule ref="WordPress.WP.AlternativeFunctions.file_system_operations_fclose">
68+
<exclude-pattern>includes/class-filesystem-direct\.php</exclude-pattern>
69+
</rule>
70+
71+
<rule ref="WordPress.WP.AlternativeFunctions.file_system_operations_fwrite">
72+
<exclude-pattern>includes/class-filesystem-direct\.php</exclude-pattern>
73+
</rule>
74+
75+
<rule ref="WordPress.PHP.NoSilencedErrors.Discouraged">
76+
<exclude-pattern>includes/class-filesystem-direct\.php</exclude-pattern>
77+
</rule>
78+
6279
<!-- Exclude test classes from naming conventions. -->
6380
<rule ref="WordPress.Files.FileName.InvalidClassFileName">
6481
<exclude-pattern>/tests/phpunit/*</exclude-pattern>
@@ -82,4 +99,10 @@
8299
<rule ref="WordPress.WP.AlternativeFunctions.unlink_unlink">
83100
<exclude-pattern>/tests/phpunit/*</exclude-pattern>
84101
</rule>
102+
<rule ref="WordPress.WP.AlternativeFunctions.file_system_operations_mkdir">
103+
<exclude-pattern>/tests/phpunit/*</exclude-pattern>
104+
</rule>
105+
<rule ref="WordPress.WP.AlternativeFunctions.file_system_operations_rmdir">
106+
<exclude-pattern>/tests/phpunit/*</exclude-pattern>
107+
</rule>
85108
</ruleset>

tests/phpunit/includes/Debug_UnitTestCase.php

+15-15
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,26 @@ abstract class Debug_UnitTestCase extends WP_UnitTestCase {
1313
protected static $log_file;
1414

1515
/**
16-
* Previously created filesystems.
16+
* The class for use with the Reflection API.
1717
*
18-
* @var array
18+
* @var \ReflectionClass
1919
*/
20-
protected static $filesystems = [];
20+
protected static $reflection;
2121

2222
/**
23-
* The original value of $wp_filesystem before any tests run.
23+
* The default filesystem.
2424
*
25-
* @var WP_Filesystem_Base|null|false False if not already set.
25+
* @var \AspireUpdate\Filesystem_Direct|null
2626
*/
2727
protected static $default_filesystem;
2828

29+
/**
30+
* Previously created filesystems.
31+
*
32+
* @var array
33+
*/
34+
protected static $filesystems = [];
35+
2936
/**
3037
* Gets the log file's path, and deletes if it exists before any tests run.
3138
* Backs up the default filesystem.
@@ -48,11 +55,8 @@ public static function set_up_before_class() {
4855
unlink( self::$log_file );
4956
}
5057

51-
if ( isset( $GLOBALS['wp_filesystem'] ) ) {
52-
self::$default_filesystem = $GLOBALS['wp_filesystem'];
53-
} else {
54-
self::$default_filesystem = false;
55-
}
58+
self::$reflection = new ReflectionClass( '\AspireUpdate\Debug' );
59+
self::$default_filesystem = self::$reflection->getStaticPropertyValue( 'filesystem' );
5660
}
5761

5862
/**
@@ -83,11 +87,7 @@ public function tear_down() {
8387
unlink( self::$log_file );
8488
}
8589

86-
if ( false === self::$default_filesystem ) {
87-
unset( $GLOBALS['wp_filesystem'] );
88-
} else {
89-
$GLOBALS['wp_filesystem'] = self::$default_filesystem;
90-
}
90+
self::$reflection->setStaticPropertyValue( 'filesystem', self::$default_filesystem );
9191

9292
parent::tear_down();
9393
}

tests/phpunit/includes/class-ap-fake-filesystem.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
require_once ABSPATH . 'wp-admin/includes/class-wp-filesystem-base.php';
44
require_once ABSPATH . 'wp-admin/includes/class-wp-filesystem-direct.php';
55

6-
class AP_FakeFilesystem extends WP_Filesystem_Direct {
6+
class AP_FakeFilesystem extends AspireUpdate\Filesystem_Direct {
77
/**
88
* Whether paths should exist.
99
*

0 commit comments

Comments
 (0)