[wp-trac] [WordPress Trac] #56966: Updating plugins with WP6.1 creates .maintenance file and leaves it
WordPress Trac
noreply at wordpress.org
Sat Nov 5 00:23:35 UTC 2022
#56966: Updating plugins with WP6.1 creates .maintenance file and leaves it
-------------------------------------------------+-------------------------
Reporter: jsh4 | Owner: (none)
Type: defect (bug) | Status: new
Priority: normal | Milestone: 6.1.1
Component: Upgrade/Install | Version: 6.1
Severity: normal | Resolution:
Keywords: has-testing-info needs-testing | Focuses:
needs-patch dev-feedback |
-------------------------------------------------+-------------------------
Changes (by costdev):
* keywords: has-testing-info needs-testing needs-patch => has-testing-info
needs-testing needs-patch dev-feedback
Comment:
I've reproduced the issue using ProFTPD. After looking into this, I'm
going to step through each part below.
This is a long one.
-----
[https://github.com/WordPress/wordpress-develop/blob/trunk/src/wp-
admin/includes/class-wp-upgrader.php#L894-L907 maintenance_mode()] calls:
{{{#!php
<?php
$file = $wp_filesystem->abspath() . '.maintenance';
$wp_filesystem->delete( $file );
}}}
Note the signature of [https://github.com/wordpress/wordpress-
develop/blob/2dce57706fa56db2e931be853ee036049921884f/src/wp-
admin/includes/class-wp-filesystem-ftpext.php#L387
WP_Filesystem_FTPext::delete()]:
{{{#!php
<?php
public function delete( $file, $recursive = false, $type = false )
}}}
`WP_Filesystem_FTPext::delete()` contains this:
{{{#!php
<?php
if ( 'f' === $type || $this->is_file( $file ) ) {
return ftp_delete( $this->link, $file );
}
}}}
`maintenance_mode()` doesn't pass the `$type` argument, so let's focus on
`$this->is_file( $file )`.
[https://github.com/wordpress/wordpress-
develop/blob/2dce57706fa56db2e931be853ee036049921884f/src/wp-
admin/includes/class-wp-filesystem-ftpext.php#L437-L439
WP_Filesystem_FTPext::is_file()]
{{{#!php
<?php
public function is_file( $file ) {
return $this->exists( $file ) && ! $this->is_dir( $file );
}
}}}
`! $this->is_dir( $file )` returns `true`, which is fine, so let's focus
on `$this->exists( $file )`.
[https://github.com/wordpress/wordpress-
develop/blob/2dce57706fa56db2e931be853ee036049921884f/src/wp-
admin/includes/class-wp-filesystem-ftpext.php#L421-L427
WP_Filesystem_FTPext::exists() - 6.1]
{{{#!php
<?php
public function exists( $path ) {
if ( $this->is_dir( $path ) ) {
return true;
}
return ! empty( ftp_rawlist( $this->link, $path ) );
}
}}}
Let's go ahead and skip `$this->is_dir( $path )` as we know this returns
`false`.
On to `ftp_rawlist()`...
Most FTP servers have the `-a` enabled by default. This includes hidden
files, and so for these servers, an existing `.maintenance` file will
return a non-empty result from `ftp_rawlist()`, meaning the file exists.
✅
However, ProFTPD doesn't include this switch by default, so won't pick up
the file. ❌
In addition, including the switch when an FTP server already includes it
can throw an error, so we can't just call `ftp_rawlist( $this->link, ' -a
' . $path )`. ❗
-----
Therefore, from what I've seen so far, we need to:
1. Call `ftp_rawlist()` without the switch. This will cover:
- Existing non-hidden files. ✅
- Existing hidden files on FTP servers who enable the switch by default.
✅
2. If the file doesn't exist, we then call `@ftp_rawlist()` ''with'' the
switch. This will cover:
- Existing hidden files on FTP servers who don't enable the switch by
default. ✅
- **Note:** The `@` operator is needed to suppress errors when `$file`
doesn't exist on FTP servers that enable the switch by default. I know,
[https://core.trac.wordpress.org/ticket/24780 we're trying to reduce the
usage of this operator], and I still need to reproduce the error to see if
it's a fatal, as `@` [https://php.watch/versions/8.0/fatal-error-
suppression won't work on PHP8+] in that case.
This looks like:
{{{#!diff
<?php
public function exists( $path ) {
if ( $this->is_dir( $path ) ) {
return true;
}
if ( ! empty( ftp_rawlist( $this->link, $path ) ) ) {
return true;
}
+ /*
+ * Include '-a' switch for FTP servers that do not enable it by
default.
+ *
+ * For some FTP servers that enable the switch by default,
including the
+ * switch again can produce an error, so the '@' operator must be
used.
+ */
+ if ( ! empty( @ftp_rawlist( $this->link, ' -a ' . $path ) ) ) {
+ return true;
+ }
return false;
}
}}}
Now, that requires confirmation of the type of error thrown, as well as
discussion on whether this approach is agreeable to committers.
For those unfamiliar, the aim of #51170 was to make
`WP_Filesystem_FTPext::exists()` compliant with [https://www.rfc-
editor.org/rfc/rfc959 RFC 959] (CTRL+F `NAME LIST (NLST)` for
`ftp_nlist()` - 6.0, `LIST (LIST)` for `ftp_rawlist()` - 6.1). The current
implementation, and the above code block, are compliant with RFC 959. The
implementation up to WordPress 6.0 was not.
I've tested the above code block on vsftpd, PureFTPd and ProFTPD, and it's
successful on all three.
For `WP_Filesystem_FTPext`, this means:
- `::exists()` will continue to be RFC 959 compliant.
- `::exists()` will work with FTP servers that do/do not enable the `-a`
switch by default.
-----
Adding `dev-feedback`.
I also still need to find out what type of warning/error is thrown on FTP
servers that already enable the switch and `-a` is passed with
`ftp_rawlist()`. FileZilla server does this, so if anyone can set up
WordPress to use `define( 'FS_METHOD', 'ftpext' )` running FileZilla
server, implement the above change, remove the `@` operator, and call
`::exists()` on a file that doesn't exist, that would be great!
--
Ticket URL: <https://core.trac.wordpress.org/ticket/56966#comment:12>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform
More information about the wp-trac
mailing list