Skip to content

Commit 0140ef3

Browse files
Treat zip files as zip files regardless of file name (#58)
## Motivation for the change, related issues There are cases where we are processing a treating a zip file as a PHP file due to a file name ending in ".php". A zip file downloaded by plugin-proxy.php may end up with the name "plugin-proxy.php" due to how FetchResource works: https://github.com/WordPress/wordpress-playground/blob/0deba0eacfd4a4c3057e6ad58e1b0cab177195af/packages/playground/blueprints/src/lib/resources.ts#L366-L368 We could tweak how we name downloaded resources to avoid this particular issue, but in general, we cannot determine the name of downloaded resources based on URL alone. Any kind of URL can point to a zip file, and the web server may or may not respond with a suggested name for a resource. There are cases where we need a default file name, and at the moment, we default to a name based on the URL path. IMO, this is fine. We can take responsibility for what we do with the fetched data in the steps that use it. In this case, let's update the installPlugin step to to treat a zip file as a zip even if its name ends in ".php". ## Implementation details This PR updates the installPlugin step to check if a file is a zip before treating it as any other file type based on extension. Before this change, the step assumes every file with a name ending in ".php" is a single file WordPress plugin. (I introduced this single-php-file install behavior in 6c54e29). ## Testing Instructions (or ideally a Blueprint) - CI
1 parent 2126101 commit 0140ef3

File tree

1 file changed

+33
-12
lines changed

1 file changed

+33
-12
lines changed

packages/playground/blueprints/src/lib/steps/install-plugin.ts

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -109,19 +109,24 @@ export const installPlugin: StepHandler<
109109
'targetFolderName' in options ? options.targetFolderName : '';
110110
let assetFolderPath = '';
111111
let assetNiceName = '';
112+
113+
const looksLikeZipFile = async (file: File): Promise<boolean> => {
114+
if (file.name.toLowerCase().endsWith('.zip')) {
115+
return true;
116+
}
117+
118+
const filePrefix = new Uint8Array(await file.arrayBuffer(), 0, 4);
119+
// Check against the signature for non-empty, non-spanned zip files.
120+
const matchesZipSignature =
121+
filePrefix[0] === 0x50 &&
122+
filePrefix[1] === 0x4b &&
123+
filePrefix[2] === 0x03 &&
124+
filePrefix[3] === 0x04;
125+
return matchesZipSignature;
126+
};
127+
112128
if (pluginData instanceof File) {
113-
if (pluginData.name.endsWith('.php')) {
114-
const destinationFilePath = joinPaths(
115-
pluginsDirectoryPath,
116-
pluginData.name
117-
);
118-
await writeFile(playground, {
119-
path: destinationFilePath,
120-
data: pluginData,
121-
});
122-
assetFolderPath = pluginsDirectoryPath;
123-
assetNiceName = pluginData.name;
124-
} else {
129+
if (await looksLikeZipFile(pluginData)) {
125130
// Assume any other file is a zip file
126131
// @TODO: Consider validating whether this is a zip file?
127132
const zipFileName =
@@ -139,6 +144,22 @@ export const installPlugin: StepHandler<
139144
});
140145
assetFolderPath = assetResult.assetFolderPath;
141146
assetNiceName = assetResult.assetFolderName;
147+
} else if (pluginData.name.endsWith('.php')) {
148+
const destinationFilePath = joinPaths(
149+
pluginsDirectoryPath,
150+
pluginData.name
151+
);
152+
await writeFile(playground, {
153+
path: destinationFilePath,
154+
data: pluginData,
155+
});
156+
assetFolderPath = pluginsDirectoryPath;
157+
assetNiceName = pluginData.name;
158+
} else {
159+
throw new Error(
160+
'pluginData looks like a file ' +
161+
'but does not look like a .zip or .php file.'
162+
);
142163
}
143164
} else if (pluginData) {
144165
assetNiceName = pluginData.name;

0 commit comments

Comments
 (0)