Linux 软件免费装
Banner图

Medifence – Access Control for Media Uploads

开发者 redwoodcity
更新时间 2026年7月30日 01:26
PHP版本: 7.4 及以上
WordPress版本: 7.0
版权: GPLv2 or later
版权网址: 版权信息

标签

media membership access control protection uploads

下载

1.10.0 1.11.0 1.12.0 1.14.0 1.15.0 1.18.0 1.19.0 1.24.0 1.26.0 1.27.0 1.3.0 1.31.0 1.32.0 1.33.0 1.35.0 1.43.0 1.44.0 1.48.0 1.49.0 1.5.0 1.50.0 1.52.0 1.53.0 1.53.1 1.7.0 1.9.0 1.13.0 1.17.0 1.6.0 1.0.0 1.1.0 1.16.0 1.19.1 1.2.0 1.20.0 1.21.0 1.22.0 1.23.0 1.25.0 1.28.0 1.29.0 1.3.1 1.30.0 1.34.0 1.36.0 1.37.0 1.38.0 1.39.0 1.4.0 1.40.0 1.41.0 1.42.0 1.45.0 1.46.0 1.47.0 1.51.0 1.54.0 1.55.0 1.56.0 1.57.0 1.58.0 1.59.0 1.60.0 1.61.0 1.62.0 1.63.0 1.63.1 1.8.0

详情介绍:

By default, every file inside the WordPress uploads directory can be opened by anyone who knows its URL. For membership sites this means that protected content pages are useless if the images inside them can still be opened directly. Medifence puts a login check in front of every uploads request — without changing a single URL and without moving any files. How it works On activation, the plugin writes a small rule block into the .htaccess file inside your uploads directory (using WordPress's own marker mechanism, so rules from other plugins are preserved). Requests for existing files are rewritten to WordPress itself, which bootstraps normally; the plugin then verifies the visitor is logged in and streams the file. No WordPress core file is ever loaded directly. Deactivating or uninstalling the plugin removes the rules, and your files are served normally again. Features Requirements This plugin does not work on nginx, because nginx does not read .htaccess files. The built-in live test will tell you immediately whether your server is compatible. For developers The final access decision can be filtered: add_filter( 'medifence_allow_access', function ( $allowed, $file_path ) { // Example: always allow files inside uploads/public/. if ( false !== strpos( $file_path, '/uploads/public/' ) ) { return true; } return $allowed; }, 10, 2 );

安装:

  1. Upload the medifence folder to /wp-content/plugins/, or install it from the Plugins screen.
  2. Activate the plugin. The .htaccess rules are written automatically.
  3. Go to Media → Access Control and confirm that the live test reports "Anonymous access is blocked".
  4. Optionally, open a media file URL in a private browsing window to verify it yourself.

屏幕截图:

  • The protection scope: excluded and protected folders, the image sizes anyone may see, and per-folder capabilities
  • What a denied visitor receives, how an allowed file is delivered, the notifications, and the record of which administrator changed the protection
  • The audit: which files anyone can open and why, files no attachment points at, what became reachable since the last count — and the list as CSV
  • Share links: expiring signed links with a password, a download limit, a note, a list you can narrow, and a ledger to download
  • The .htaccess rules the plugin generates

升级注意事项:

1.63.1 Screenshots and their captions updated for the current screens. No change to the plugin itself. 1.63.0 Adds a setting for whether allowed files open in the browser or always arrive as a download. 1.62.0 The media library list can now be narrowed to protected files, or to the ones anyone can open. 1.61.0 The list of active share links can now be searched, filtered by state, and paged through. 1.60.0 Adds a built-in placeholder image, so denied images can look deliberate without preparing one. 1.59.0 The audit's list of publicly reachable files can now be downloaded as CSV from the admin screen. 1.58.0 The access log now counts refused share links and wrong passwords, so a link that "does not open" can be traced. 1.57.0 Bulk-issued share links can now be emailed as one message, and a link can be started from a file's edit screen. 1.56.0 Denied visitors are now told which file they were opening, on the login screen and on your own page. 1.55.0 Publishing a post now warns when it links to media your visitors will not be able to open. 1.54.0 Warns when your media URLs point at another host, where this plugin is never asked who may open them. 1.53.1 Refreshed screenshots only. The plugin itself is unchanged from 1.53.0. 1.53.0 The active share links can now be downloaded as a CSV ledger — without the links themselves. 1.52.0 A freshly issued share link can now be emailed straight from the result box. 1.51.0 The share forms' preselected lifetime and download limit are now configurable. Existing behaviour is unchanged until you change them. 1.50.0 Adds a dashboard widget with the protection's vital signs, for administrators. 1.49.0 The audit and the increase email now name the files that became reachable since the previous daily count. 1.48.0 The daily reachable-files count now runs independently of the email notification, and the status tab shows a 30-day trend. 1.47.0 Repeated overwrites of the rules are now reported as a standing plugin conflict instead of being repaired silently. 1.46.0 Adds the MEDIFENCE_LOCK_SETTINGS constant to freeze the protection scope. Nothing changes until you set it. 1.45.0 Site Health now also reports excluded document types and the last count of reachable media files. 1.44.0 Adds --format=json to wp medifence status and inspect, for deployment scripts. Exit codes are unchanged. 1.43.0 WebP/AVIF copies made by image optimizers now follow the protection of the file they were made from. 1.42.0 Repairs now keep what was overwritten, so you can identify the plugin that keeps rewriting the rules. 1.41.0 Settings changes recorded from now on can be undone with one click from the history. 1.40.0 The audit now lists the attachments whose file is missing on disk, not just how many there are. 1.39.0 The status tab and Site Health now warn when WP-Cron is not running the scheduled checks. 1.38.0 Adds the [medifence_files] shortcode: a folder listing that only shows what the current visitor may download. 1.37.0 The Audit tab can now find protected files embedded in published posts — the ones visitors see as broken images. 1.36.0 Excluding document or archive extensions now shows a warning before and after saving. Nothing is blocked, and existing settings are unchanged. 1.35.0 The media dialog now shows whether a file is protected while you insert it, and administrators get a read-only REST field with the verdict. 1.34.0 The access log's size and retention are now configurable, and the log tab shows a per-day count for the last week. Defaults are unchanged. 1.33.0 Adds an optional weekly summary email. Nothing is sent until you switch it on. 1.32.0 Share links can now carry an optional password as a second factor. Existing links are unaffected. 1.31.0 Deleting a file now also revokes its share links, so the list only shows links that can still be used. No settings change. 1.30.0 Thumbnails can now be published while the original stays protected. Nothing is published until you tick a size, so existing settings are unaffected. 1.29.0 The audit can now cover a library of any size, a batch at a time. wp medifence audit defaults to the whole library. 1.28.0 Adds per-folder capability rules for sites with several membership tiers. Existing settings are unaffected. 1.27.0 The audit list can now protect the files it reports, in place. No change to how files are protected. 1.26.0 Adds a media library bulk action for creating share links for several files at once. Existing links are unaffected. 1.25.0 The daily check now also warns when more files become reachable. Only active if the email notification is already on. 1.24.0 Adds a scan of the uploads directory for files the media library does not know about. No functional changes to the protection itself. 1.23.0 Adds a history of who changed the protection settings. Recording starts from this version. 1.22.0 Adds the option to send denied visitors to a page of your own. The default behaviour is unchanged. 1.21.0 Adds settings export and import as JSON, reviewed before it is applied. Existing settings are unaffected. 1.20.0 Adds a preview that shows which files a settings change would expose, before you save it. Existing settings are unaffected. 1.19.1 Fills in the Help tab for the access log, the CSV download, and the pause commands. Documentation only. 1.19.0 Adds a CSV download for the access log. No change to how files are protected. 1.18.0 Adds a temporary pause for the protection that always ends by itself. Nothing changes until you use it. 1.17.0 Adds a folder picker and validation to the scope settings. No change to how files are protected. 1.16.0 Adds an optional email notification when the protection state changes. It is off until you switch it on. 1.15.0 Adds per-file exceptions (always public / always protected). Existing settings are unaffected. 1.14.0 Adds an optional access log counting what was blocked, per file. It is off until you switch it on. 1.13.0 Adds an Audit tab listing every file your settings leave public. No functional changes to the protection itself. 1.12.0 Adds download limits and notes for share links. Existing links keep working unchanged. 1.11.0 Replaces the attachment ID fields with a media library picker. 1.10.0 Adds an Access column to the media library so you can see what is protected at a glance. 1.9.0 Adds a file inspector that explains why any given file is protected or public. 1.8.0 Reorganises the settings screen into tabs and adds a Help tab. No functional changes. 1.7.0 Adds a list of active share links with individual revocation. Share links issued before this version stop working; re-issue any you still need. 1.6.0 Adds an option to send visitors to the login screen when they open a protected file. The default behaviour is unchanged. 1.5.0 Adds a protection scope that follows each file's parent post. Existing settings are unaffected. 1.4.0 The settings screen moved from Settings to Media → Access Control. 1.3.1 Adds a Japanese translation. No functional changes. 1.3.0 Adds automatic repair of the rules, a Site Health test, and WP-CLI commands. 1.2.0 Adds expiring share links for granting access to individual files without an account. 1.1.0 Adds folder-level control over what is protected. Existing settings keep working unchanged. 1.0.0 Initial release.

常见问题:

Do my file URLs change?

No. Existing URLs in posts, themes, and the database keep working exactly as before. Logged-in visitors see no difference at all.

How do I know the protection is actually working?

The settings screen runs a live test: it creates a temporary file, requests it over HTTP without any session cookie, deletes it, and reports the status code. If your server configuration prevents the rules from working, you will see it there — not months later.

Does it work on nginx?

No. The plugin relies on .htaccess rewrite rules, which nginx does not support. You would need an equivalent rule in your nginx configuration, which is outside what a plugin can safely manage.

What happens when I deactivate the plugin?

The rules are removed from the .htaccess file and all files are served normally again. Uninstalling additionally deletes the plugin's settings.

Another plugin overwrote the .htaccess file. What now?

Medifence detects this and shows a warning on your admin screens. One click on "Regenerate .htaccess rules" restores them. A daily scheduled check also rewrites the rules on its own, so the protection comes back even if nobody logs in; you can turn that off in the settings.

Will I hear about it if the protection breaks while nobody is logged in?

Switch on the email notification in the settings. The daily check then sends one message when it finds that anonymous visitors can reach your files, and one more when the protection works again. It is sent only when the verdict changes, so a problem that persists does not fill your inbox, and a live test that could not reach the site at all is never reported as a failure. Use "Send a test email" first to confirm that this site can send mail at all.

Will I hear about it if someone widens the protection scope?

Yes, if the email notification is on. The live test answers "do the rules work", and a widened scope leaves that answer green — the rules work exactly as configured, and it is the configuration that changed. So the daily check also counts how many files a logged-out visitor can open, and writes to you when that number grows. A number that falls is never reported: locking more files down is not news. The message names a few of the files and links to the Audit tab, which lists all of them with the reason for each. The settings tab records which administrator last changed the protection. The daily count examines the newest 500 attachments; the medifence_exposure_limit filter changes that.

Does this modify files outside the plugin directory?

Yes, one file: the .htaccess inside your uploads directory. The plugin uses WordPress's insert_with_markers() function, which only touches its own marked block and preserves everything else. The block is removed on deactivation and uninstall.

Does the plugin contact any external service?

No. The live test sends one HTTP request to your own site. Nothing is sent anywhere else.

Does the plugin store personal data?

Nothing about your visitors. The optional access log records the file path, what happened to it, and when — no IP addresses, no user agents, and no user names. It is off unless you switch it on, keeps at most 200 files for 30 days, and can be cleared with one click. The settings history is the one place a person is named, and only an administrator of your own site: when the settings that decide access change, it records which user account made the change. That is the point of it — a protection that was widened should be traceable. It keeps the last 50 changes and can be cleared with one click.

How do I find out which files my visitors are actually blocked from?

Switch on the access log in the settings, then look at the Access log tab. It counts per file what Medifence did: blocked the request, served the placeholder, sent the visitor to the login screen, accepted a share link — or refused one, because it had expired, been revoked, or been used up, with wrong passwords counted separately. A file that is blocked over and over is usually one your theme or another plugin needs for everyone — exclude its extension or its folder. The list can be downloaded as CSV from the same tab — one row per file, with one column per event — or produced on the command line with wp medifence log --format=csv.

Does this slow down my site?

Protected files are served through PHP, which adds overhead compared to direct file delivery. To keep this small, the plugin sends ETag headers so browsers of logged-in users cache files locally, and repeat requests are answered with an empty 304 response. Files with excluded extensions bypass PHP entirely.

A file is still reachable right after I enabled the protection. Why?

Files that were served before the protection was active — or while their folder or extension was excluded — may still sit in a server-side or CDN cache, and that copy is served without ever reaching WordPress. Medifence sends Cache-Control: private on everything it delivers itself, so protected files are never stored in a shared cache; the stale copy disappears once the cache entry expires, or immediately if you purge the cache. Verify with a fresh query string (for example ?x=1), which bypasses most caches.

I serve my media from S3 or a CDN. Does this still protect them?

No — and the plugin now says so rather than leaving you to find out. When your media URLs point at another host, requests for those files never reach this server: the uploads .htaccess is not on the way, and Medifence is never asked who may open them. Everything else keeps looking healthy, which is what makes this worth naming — the rules are in place, and the live test requests a file from this site and passes. The status tab and Site Health name the host whenever the media URLs point elsewhere. Protect the files where they are actually served from, or serve the uploads directory from this site again. A CDN that caches your site as a whole is fine, as long as the media URLs still point at your domain; if your setup rewrites the URLs but the files do pass through WordPress after all, correct the verdict with the medifence_external_media filter.

My site has several membership tiers. Can gold files be closed to silver members?

Yes. Put each tier's files in its own folder and give that folder its own capability under "Folders that need more than a login" on the settings tab. A logged-in visitor without that capability is refused exactly as a logged-out one is. The most specific folder decides, so a rule on members/gold is applied ahead of one on members. Folder rules can only narrow access — they never let in someone who already failed the site-wide capability — and a share link still works for the one file it was issued for. The file inspector names the capability a given file requires, and which roles have it.

Can I keep the images in published posts public, but protect the ones in members-only posts?

Yes. Choose the "Follow the post each file is attached to" scope. A file attached to a published post is served to everyone, exactly as before the plugin was active; a file attached to a private, draft, or password-protected post requires a login. Files that belong to no post remain protected, and generated image sizes follow their original — a thumbnail is never more public than the full image.

Can visitors see the thumbnails while only members can open the full-resolution photo?

Yes. Tick the generated sizes that may be public under "Image sizes anyone may see" on the settings tab. Everything else inside the protected scope, including the original file and the -scaled copy WordPress makes of a large upload, keeps requiring a login. Which size a file is comes from what WordPress recorded when it generated it, not from the numbers in the file name, so a size that does not crop cannot slip through a coincidental -1024x1024 match. A file whose size WordPress has no record of is treated as protected. This can only open files the scope would otherwise protect. An excluded extension or folder is decided first — those files are delivered by your web server and are public regardless — and a per-file exception still overrides everything. A published size is still delivered by WordPress, so it is no faster than a protected file.

Someone clicks a protected PDF and just gets an error. Can I show the login screen instead?

Yes. Set "When access is denied" to "Send visitors to the login screen, then back to the file". After logging in they land on the file they originally asked for. The redirect applies only when the browser navigates to the file directly — an <img> or a video embedded in a page still receives the status code, so your pages never end up showing a login form where an image should be. The login screen also names the file they were opening, above the form, so the redirect reads as a closed door rather than as a site that lost their click. Only the name is shown, never the folder it sits in.

My gallery shows broken images to logged-out visitors. Can I show something instead?

Yes. Under "Placeholder image" on the settings tab, either choose an image of your own from the media library, or tick "Use the built-in image when no attachment is chosen" — a grey padlock that ships with the plugin, with no text on it, so it reads the same in every language. Denied image requests then receive that picture instead of a status code, and the layout of the page survives. The original file is never served. This applies to images only; other file types still get the status code. If a placeholder attachment you chose is deleted later, the built-in image stands in for it, provided the tick box is on.

A page is broken and I suspect the plugin. Do I have to deactivate it to check?

No. Use "Pause the protection" on the Protection status tab: every file is served as if the plugin were inactive, but the .htaccess rules stay in place and the protection resumes automatically after the time you chose — 5 minutes up to 1 hour, so it cannot stay off by accident. While the pause lasts, responses carry an X-Medifence: paused header, a warning shows on every admin screen, and the email notification does not report the pause as a failure. Also available as wp medifence pause and wp medifence resume.

What about files in the uploads directory that are not in the media library?

They are protected by the same rules — the scope works on paths, not on the database — but until now nothing reported on them, because the audit walks the media library. "Scan the uploads directory" on the Audit tab walks the directory instead and lists the files no attachment points at which a logged-out visitor can still open: an export another plugin left behind, a leftover from a migration, something copied in over FTP. Generated image sizes, the scaled copy of a large upload, and edited versions are resolved back to their original, so they are not reported as strays. Also available as wp medifence stray.

Can I set this up on staging and copy the configuration to the live site?

Yes. "Download the settings" on the settings tab writes a JSON file, and "Read a settings file" on the other site reads it back. Only the settings travel — share links, the signing key, the access log, and per-file exceptions belong to one site and are never exported. An imported file is not applied on the spot. It fills in the form as an unsaved change and reports what it would do to that library, so a scope that made sense on staging cannot quietly expose files on the live site. Press save once the effect looks right. On the command line, wp medifence export --file=medifence.json and wp medifence import medifence.json do the same, and --dry-run reports the effect without saving.

I want to change the protection scope, but I am afraid of exposing something.

Use "Preview the effect" next to the save button. It applies the values currently in the form to your media library without saving them, and reports which files would change side — the ones that would stop being protected first, since that is the direction that matters. Your edits stay in the form, so you can then save them or discard them. Nothing is written until you press save.

The login screen is the wrong answer for people who have no account yet.

Set "When access is denied" to "Send visitors to a page of your own" and pick a published page — a membership page, a contact form, whatever explains how to get access. The file they tried to open is added to the URL as mf_from, and the [medifence_requested_file] shortcode prints its name, so the page can say "You tried to open [medifence_requested_file]" without any PHP. Opened directly, with no file behind it, the shortcode prints nothing — so write the sentence to still read sensibly then. The same rule as the login redirect applies: it only happens when someone opens the file in their browser. An image or a video embedded in a page still receives the status code, so your pages never show a membership page where a picture should be. If the chosen page is later unpublished or trashed, denied visitors quietly fall back to the status code rather than being sent into a 404.

The audit found files anyone can open. How do I close them?

From the list itself. Tick the ones that should not be open and press "Set the selected files to always protected" — that stores a per-file exception without touching the protection scope, so nothing else moves. The library is scanned again straight afterwards, so whatever is still listed is still reachable. Some files cannot be closed this way, and are reported separately. A per-file exception is decided in PHP, so it only works for files the rules actually route through WordPress. A file your web server delivers itself — because its extension is excluded, its folder is excluded, or the scope is limited to other paths — never reaches the plugin at all, and only a change to the scope closes it.

My published post shows broken images to visitors. Why, and how do I catch it earlier?

Because the post links to files the protection keeps closed: you are logged in and see them, a visitor is not and does not. It is the one misconfiguration this plugin can create, and it looks perfectly fine to whoever wrote the post. Publishing a post now checks that post for such files and names them in a notice, with a link back to the post — no scan to remember, and nothing is blocked: the post is saved either way. Since the block editor saves in the background, the notice appears on the next admin screen rather than the instant you press publish. A post whose files are all reachable says nothing at all. To review the whole site instead, use "Scan published content" on the Audit tab. The fix is either to widen the protection for those files (an exception, an excluded folder, or the "follow the parent post" scope) or to use a public copy in the post — the audit names each file so the choice is per file.

A file is public when I expected it to be protected. How do I find out why?

Use the file inspector on the Protection status tab, or the Audit tab to see all of them at once — it applies your settings to the whole library and lists every file a logged-out visitor can open, with the reason for each. For a single file: Paste the file's URL (or enter its attachment ID or path) and it reports whether a logged-out visitor can reach it, naming the setting that decided — an excluded extension, an excluded path, a scope that does not cover it, or the status of the post it is attached to. The same check is available from the command line as wp medifence inspect <file>.

One single file has to be public (or protected), but the rest of the folder should stay as it is.

Select the file in the media library and use the bulk action "Medifence: always public" or "Medifence: always protected"; the same choice is on the file's own edit screen. That one file then ignores the protection scope, and generated image sizes follow their original. Every exception is listed on the Audit tab and can be reset there. One limit is worth knowing: "always protected" only works for files that reach Medifence at all. If the file has an excluded extension, or sits in an excluded folder, your web server delivers it directly and no plugin is asked. The file inspector says so when it happens.

Can I let someone without an account see one file?

Yes. On the settings screen, or from the "Share link" action in the media library, create a share link for that file and choose how long it stays valid. The link is the file's normal URL plus a signature, so it works for that one file only and stops working when it expires. You can also limit a link to a number of downloads — one, for a file that should be fetched exactly once — and add a note recording who it was issued to. Revalidating a cached file and seeking inside a video are not counted, so a one-download link is not spent halfway through a video. Every active link is listed on the settings screen with its expiry, how often it was downloaded, and when it was last used; each one can be revoked on its own. The list can be searched by file name or note and filtered to what expires within a day, what has one download left, or what carries a password, with pages of 50. "Revoke all share links" additionally replaces the signing key, invalidating everything issued so far at once.

Can I send someone a whole set of files?

Select them in the media library and choose the bulk action "Medifence: create share links". The lifetime, the download limit, and the note are asked once and applied to every link — so a note like the client's name ends up on all of them — and the links are then shown together, with a box holding all of them one per line for copying into a single message. Each link still covers its own file alone, and the download limit applies to each link separately rather than to the set. Up to 25 files per request. Files whose file is missing on disk are named rather than silently dropped. The whole set can be emailed from that result box, as one message listing every link with its file name and expiry — the recipient is one person, so twenty separate mails would be worse than the paste this replaces. If any of the links has been revoked between issuing and sending, nothing is sent at all.

更新日志:

1.63.1 1.63.0 1.62.0 1.61.0 1.60.0 1.59.0 1.58.0 1.57.0 1.56.0 1.55.0 1.54.0 1.53.1 1.53.0 1.52.0 1.51.0 1.50.0 1.49.0 1.48.0 1.47.0 1.46.0 1.45.0 1.44.0 1.43.0 1.42.0 1.41.0 1.40.0 1.39.0 1.38.0 1.37.0 1.36.0 1.35.0 1.34.0 1.33.0 1.32.0 1.31.0 1.30.0 1.29.0 1.28.0 1.27.0 1.26.0 1.25.0 1.24.0 1.23.0 1.22.0 1.21.0 1.20.0 1.19.1 1.19.0 1.18.0 1.17.0 1.16.0 1.15.0 1.14.0 1.13.0 1.12.0 1.11.0 1.10.0 1.9.0 1.8.0 1.7.0 1.6.0 1.5.0 1.4.0 1.3.1 1.3.0 1.2.0 1.1.0 1.0.0