This page discusses a number of known issues around the Drupal file storage mechanism, and a number of ways people have addressed them.

In brief, if you have a development site, upload images or files using that site and then take your site live using the standard methods, there is potential for links to those images to break in several ways. This has always been a risk.

Most of the worst of these issues for managed files have been resolved in Drupal 7 with the File Stream Wrappers initiative. Images "attached" as fields or uploaded through the API should normally be re-linked correctly on migration, with no more than a cache clear needed.
The remaining issues discussed mainly apply to in-page links and image embeds, such as from HTML or WYSIWYG editing, and tools like IMCE or copy and paste.

Absolute URls

The simplest cause is by editors embedding links in nodes or blocks by copy-pasting absolute URLs. This is obvious in plaintext editors, but somewhat cloaked by WYSIWYG tools.
A link like
<img src="http://dev.localhost/sites/default/files/image.jpg">
in the site content will cause problems going live. Worse, it will not be noticed in developer testing as the reference to the dev host will still resolve for *them* but not for anyone else.

Solution 1: Don't do that then

It's important that content editors at all levels learn and understand the difference between absolute URL links to offsite, Site-relative links based on the current site, Fully relative links (don't use these in Drupal), and links to files on their own desktop!
Generally, a semi-informed person in this situation should know how to chop off the absolute part of any link like this and end up with
<img src="/sites/default/files/image.jpg">
which is usually enough for things to keep working.

Solution 2: Pathologic module

This can be configured to repair a known number of these errors on-the-fly after the site goes live.

The absolute URL problem can exist for any website or CMS, and is just a speedbump for all webmasters. However, Drupal introduces a number of other complexities.

Drupal in a subfolder

Drupal allows you to deploy a site either in server root (normal) or in a server subfolder. Either of these work, but shifting between these two methods (eg developing locally in a subfolder then going live to a full domain) will potentially mess up your in-content links.

Solution 1 : Avoid subfolders

If you are planning to go live with a site developed locally, give it the root of your webserver. Switching between the two modes will be a headache.
Either use the Acquia dev desktop which manages local vhosts for you, or find the settings in your own Apache or XAMPP stack to let you make additional vhosts. You can even develop on additional *ports* on the same machine to manage multiple sites all on localhost, and that will be compatible with a Drupal site that will go-live to a full domain.

Problem: Multisite files directories

If you only ever deploy a site in sites/default and never use or plan to use multisites, Acquia tools, Aegir, drush migrations or enterprise setups, this may not affect you. However, you should be thinking about graduating to adding these to your workflow, so here's the problem:

In a multisite context, the files directory will be
/sites/dev.localhost/files/"
or
/sites/live.example.com/files/"

Standard HTML links that try to refer to these files within HTML, eg
Download our <a href="/sites/dev.localhost/files/application.pdf">application form</a> now.
will cause trouble.

Essentially, (badly in Drupal 6 and earlier, much less in Drupal 7) you may be required to go through the steps of modifying the file system path on every site release.

A number of workarounds exist. Most with some issues - don't take this list as recommendations!

Solution: Make a symlink (or directory alias)

The first time this happens, and you find that a lot of links on the live site are broken on go-live, a quick patch (if you have the ability) is to make a symlink, either to the sites or the files directory

/sites/dev.localhost/files/ -> sites/dev.localhost/files/

A similar result can be obtained with the use of an Apache DirectoryAlias in the .htaccess file.

Issues

* It's unsustainable long term, and it's an awkward thing to deploy.
* Bad or confusing SEO. The same content (image or document) now has two equally valid paths, either or both may be in use on the site, and there is no visible pressure to fix this.
* Symlinks can confuse some tools. Not just web spiders, but some IDEs, FTP clients or backups could find themselves reading double-ups of your entire files directory. This is not such an issue with the DirectoryAlias approach.
* Your links remain "bad" rather than being fully migrated to the correct new URL patterns.
* If you migrate a third time (or have a UAT/Staging host too, the need for this workaround triples.
* Symlinks have other issues (security) #1008402: Allow the use of symlinks within the files directory.

Solution: Do some database rewrites on migration

Simply, when doing an SQL migration, you need to substitute file URLs of the old form to the new form. Snippets such as

UPDATE node_revisions SET 
  body = replace( body, "sites/OLD_SITE_NAME", "sites/NEW_SITE_NAME" ) ;

make an OK attempt at this. This can also (sometimes) be done with a string replace run directly over the SQL raw file between migration steps also.

$ sed 's/dev\.example\.com/www.example.com/gi' dev-dump.sql > prod-dump.sql

This does repair the issue at source, so when done right, it works.

Issues

* It's an extra step and you have to find a way to ensure it's done each time.
* There can be dodgy errors introduced if you don't get the syntax just right. The string-replace on the SQL is highly risky.
* With the Drupal 7 field API, there are a large number of *other* places that also need updating. Other text fields, block freetext content, revisions, comments, even Views headers or anything editable through the UI. A raw database attack cannot be complete any more.

* I THINK Aegir site migrations do something like this in the background somewhere.

Again, Pathologic should be able to help cover up this issue if you've already gone live - though it won't repair the cause. Another module Site dir migrate will do the rewrites for you also, and is drush-enabled.

Preventing the problem

Previous examples are about what to do once things have gone wrong. Now you know about this issue, perhaps you can avoid it in the future. Here are a few methods I've seen.

Solution: Nominate a single storage path that doesn't change with site migrations

By 'fixing' the sites file path, eg I've seen the made-up paths sites/all/files or sites/public_files a few advantages can be gained.

* It pretty much removes the portability issue
* It can save file copy overhead which can be significant for huge folders

A variation of this can even combine symlinks with a single fixed directory.

Issues

* It's not very "Drupally", as it works against the system rather than within it. This can cause cognitive problems for developers who actually follow the documentation.
* It is totally incompatible with 'multisite' but works well enough for dev/staging/live workflows.
* It's weirder to backup, as your 'site' info is no longer where it should be. This may confuse tools such as drush.
* It sorta confuses upgrade reports as it makes use of a non-standard file location, which may or may not be a problem.

Solution: Use plugins so you never add full paths to files

I think media.module and insert.module take extra care to embed tokenized paths when they embed into HTML. Check this.

portable_path.module

explicitly does this, by tokenizing the path on save, and making it relative on display later. This is probably the most graceful fix to the whole issue. If it works, it should be totally transparent.

The only possible issue is that once it's in use, it can't be turned off as it is required from then on for your content to be rendered correctly. This applies to most tokenizing or markdown utilities, so it's not a great concern to many users.

file_aliases.module also seems to support tokenizing of file paths and advertises "no more '/sites/default/files/'"

Solution: Or solve the problem of site-specific paths altogether, and prettify URLs at the same time #

Aegir hosting, which is one of the larger culprits for making this issue more common with how it renames site folders so much, has an interesting work-around.

  # Allow files to be accessed without /sites/fqdn/
  RewriteRule ^files/(.*)$ /sites/%{HTTP_HOST}/files/$1 [L]

What this means (you don't have to read that) is that in any case where you previously would have had to use

<img src="/sites/site.name/files/image.jpg">
you can immediately stop doing that and just use
<img src="/files/image.jpg">
instead. And when you move to a new host, that link will continue to work, transparently serving the localized files without anyone noticing.
This is not only more convenient and portable. It's also arguably a lot tidier to work with, read, or debug.

There is a question about whether this solution has any significant performance impact. But it feels like a step forward out of the whole mess of issues described above.

Do it yourself

Even if not using Aegir, you can employ their trick by just adding that line to your own .htaccess file.

Beware Acqua or WAMP users:

If you are using this trick on a local machine that uses alternate ports, you should use SERVER_NAME not HTTP_HOST as HTTP_HOST contains the port - which is not Acquia compatible.

At the top of the rewrite rules

<IfModule mod_rewrite.c>
  RewriteEngine on

  # Allow files to be accessed without /sites/fqdn/
  RewriteRule ^files/(.*)$ /sites/%{SERVER_NAME}/files/$1 [L]
  ...
  ..

If you use this, the rest of the use of the site will proceed as normal, and it's up to you to make use of this hidden shortcut if editing HTML by hand.

Make this method part of your workflow

Dane Powel experimented with a utility to make all managed site files use the short path by default and there is an unsupported snippet to
make IMCE link to files using this canonical short path

Issues

Both of these are totally unsupported and *will* have side effects against some other modules. aegir-prettyfiles (current version) will not work with image(cache) generation at all, so really, don't use it without further work.

There are probably many more issues to be uncovered.
* Performance?
* This appears to re-introduce the duplicate content issue that symlinks or aliases do, unless the rewrite is made into a 301 redirect, or all traces of the old path are totally cloaked.
* Interaction with other modules. Unknown, but anything that has converted COMPLETELY to the file stream wrapper API will probably be able to handle this concept.

TODO

This general approach could be extended into Drupal as a long term solution, or at least, by gathering the snippets together into a project, with a bunch of tests, it could become a tool in the site builders kit.

Please link to other solutions or discussions that may extend this topic.