Little bit of background information: The previous project manager was fired due to not delivering the project on time. I have little experiencing coding, but am now leading the team to finish the website.
The website itself is similar with Ebay where an item is added for sale. Images and documents will are associated with the item, but hosted in folders that are created when the image is uploaded. The dev team has asked me "how to manage the folders with the documents in relation to the item listing". There will be between 1-10 images/documents uploaded per item and will be between 1000-2000 items listed at one point in time (if not more).
From looking around, I believe the easiest solution is to name the folder by the item number and list the reference in MySql. Each item will have an individual item number and should be no duplicates. Are there better solutions for the folder management?
As mister said images could be renamed with the productid-docid-imageid-timestamp
If the images are not retrieved very often storing the images in db as blob and printing the image with different name may help.
What you want to be careful with is that most filesystems have a limit on how many items can be stored in a folder; on Linux the limit is typically around 30000. With the numbers you give there should be little concern there, but you should still plan for the system to be future proof.
I have found it to be quite useful to store images by their hash. For instance, create a SHA1 hash of the image, e.g.: cce7190663c547d026a6bf8fc8d2f40b3b1b9ea5. Then store the image in a directory structure based on this hash with a few levels of folders:
cce/719/066/3c5/cce7190663c547d026a6bf8fc8d2f40b3b1b9ea5.jpg
This uses the first 12 characters of the hash to form a folder structure 4 levels deep, then the file name is the entire hash. Increase or decrease the folder depth as necessary. This allows you to store quite a lot of images (((16^3)^4) * limit) without hitting the filesystem limits. You then save this path in a database with other information about the image and which items it belongs to. This method also effectively de-duplicates your data storage, you'll never store the same image twice.
It used to be that filesystem performance would deteriorate if there were too many files in a directory, so the common wisdom was to limit to ~1,000 items in any directory.
Try creating a directory structure around the item_id (padded), so #1002003 might be 001002003, which could be found in 001/002/001002003.jpg.
Since you're storing more than one image per item, you might have one more level, e.g. 001/002/003/001002003_1.jpg.
Use the full ID as the item's name in the final directory (001002003.jpg, not 003.jpg). It'll come in handy later.
Hope that helps.
I created a website, and on it the users can upload different files which they can later access through their profiles. Over time, I realized that this method of creating folders and sub-folder for users and is quite cumbersome, as it creates so many folder and sub-folders as more users join and use my website. I'm now thinking of having one folder for all the files but renaming user's files on the fly to something like USERID-FILENAME.
The problem comes when I want to display the files to their specific user; I want to search the files in the folder then grab the files that start with a particular userid e.g if its user of id 200, I want to grab all files that have 200 before the first hyphen and display them.
How can I accomplish this and is it the best method to use?
You probably want something more like a database or a key-value store for this work, rather than your file-system, which will not scale well as/if your site grows significantly.
For example, you could use something like <userid>-<filename> as a key in a key-value store, with the contents of the file set as the value, encoded as a binary blob.
On top of this, you may then need a descriptor that keeps track of all the files a user has ever uploaded, perhaps keyed directly by the userid or by something like, <userid>-files
Then when you're looking up the user, you load their <userid>-files descriptor first, using this to present a list of files they access/control/own, then lookup <userid>-<filename> when they request a specific file.
Thinking on this some more, that may not be sufficient to handle cases of a user uploading the same file multiple times -- you might want to assign IDs to the files themselves, and just keep those IDs in the <userid>-files blob. This has the added advantage that the schema for storing files is user-agnostic, so you could start extending your service to implement sharing functionality (with perhaps another hunk of data describing sharing/access-control properties).
Something like this perhaps:
foreach (glob( ((int)'$userid')'-*') as $file) {
process($file);
}
Given a PHP bug tracker project with an SQL DB (MySQL, PostgreSQL, Oracle...), which should be able to store attached files for each bug.
How would you basically store info (file info and the file itself) on DB & disk?
e.g.
DB: the table bug would have a related table bug_files having a bug_id field, and a filename field containing path to file on disk
Disk: storing files in an efficient way (avoiding having too many files in a single directory), e.g. automatically create directories 1-1000, 1001-2000, etc. so we can have /1001-2000/1234/bugfile.jpg or random subdirectories like /z/e/x/q/1000_bugfile.jpg ?
...or are there a more efficient ways?
Thanks.
EDIT
It also depends on how you want to get
to these files, do you use a back-end
webpage that fetches all bugs and
creates the links for you? Or do you
get an e-mail after a bug occured and
do you have to find it manually? I
don't think this choice mathers a lot.
Files would be listed / uploaded / downloaded through the bug tracking web application (=> HTTP upload / download).
Nobody except developers / sysadmins would be able to view the automatically generated directory structure (however it would be more convenient to have a "clear" structure).
I'd let the file system do its job (file storage). Databases can be used for file storage but it's not (generally) as efficient, e.g. the file data may be put in the database buffers - this in itself isn't bad, but it may take resources away from other tables, row data and reduce the performance of other queries.
Creating directories based on a meaningful combination of date and project names etc. would help reduce the performance loss when having many files in the same directory.
I'd strongly suggest using recognizeable directory structure, perhaps even date based or something that matches up with (parts) of your bug filename. F.e. '20110506-bugfile' would be in /2011/05/06/ Perhaps this is a little to matching and only 2011/05/ would be enough.
It also depends on how you want to get to these files, do you use a back-end webpage that fetches all bugs and creates the links for you? Or do you get an e-mail after a bug occured and do you have to find it manually? I don't think this choice mathers a lot..
A slightly different option is to add the file into your database in the table bug (http://www.php-mysql-tutorial.com/wikis/mysql-tutorials/uploading-files-to-mysql-database.aspx), then you don't have to create a directory structure, BUT, this would not allow you to find the files using an FTP ofcourse.
I was wondering what is the best way to store a users upload images like an avatar and so on using PHP and MySQL? Where should I begin? And is there a good article on this?
"Best" depends on what your goal is.
The two primary ways of storing user-uploaded images are either putting the binary content into the database as a BLOB, or storing the images to the drive somewhere and putting an entry into the database indicating which image belongs where.
Placing the images in the database has the advantage of not requiring any sort of filesystem permissions on the webserver, and removes any sort of syncing issues if you're serving up the site off of multiple webservers. However, over time it makes your database huge, and if you don't design your tables correctly, it can absolutely kill your performance and scalability.
Storing the images as file on the file system has the added advantage of making retrieval extremely quick and efficient, since webservers are very good at serving static files.
Edited to add
If you decide to store file content in the database, absolutely do not put it in a table that needs to be accessed quickly. If, for example, you have a "users" table that is searched on nearly every pageview, then that table is not the place to put your file contents. Instead, create a separate "images" or "files" table containing the file and related meta-information.
Putting a lot of bytes per row into a table makes that table very slow to work with. You don't want that kind of thing in tables that see heavy use.
Images should really be stored on the file system for a couple of reasons:
Proxying and If-Modified-Since web requests: Apache can process If-Modified-Since HTTP headers for you and return a 304 response, and that's about the best performance you can get. Reverse Squid proxies and proxies posted at ISPs will attempt to take advantage of this.
Virus scanning: if you allow any file uploads, jerks will try and upload scary stuff to see if they can bust your site. It's not unreasonable to want to run ClamAV or the like against your user uploads to see if there's trouble afoot. You wouldn't want to tie up your database if you wanted to scan the records for malware.
Schema simplicity: If you allow file uploads, you'll also need to add meta data about the MIME-type, file size, height and width. If the file itself doesn't match the MIME-type in the table, then you need to code a select from the table and stream it into /usr/bin/file. It can be much simpler to shell_exec( "/usr/bin/file /path/to/mumble" ).
Thumb-nailing: user image uploads are likely to need to be thumb-nailed, and this is often much easier done asynchronous to the actual web request. It's really not fun when some well meaning user attempts to upload a 150MB photoshop file given to them by their professional photographer buddy, and your apache instance goes OOM when attempting to load the ImageMagick library in the memory space of the web worker. This really doesn't scale for apache workers. Create a work queue/cron job outside of Apache to handle this work.
Table corruption: Wow, you don't really want to cripple all user avatars if your MySQL index file gets borked and you need to do an offline table repair on that table.
Backup and restore: You don't really want to lock a large table with mysqldump. Using rsync will save you a lot of time and give you much more flexibility. Tables are typically restored a whole table a time--tables are not typically backed up in smaller pieces.
make a new directory on your server for each user with the user id being the name of the directory and save the user's images inside it. whenever you want to display the user's image:
<img src="<path>/users_images/<user_id>/thumb.gif" />
If I were you, I would just save the image somewhere in your sites directory and then save the link to the image in MySQL, if you really want to save it in a database, I would read it into a string and then base64_encode() it and then save it in the database.
There are all sorts of little troubles you will face by storing them in a database, you will have to create scripts to echo them back out ect, and the server and database load will be greatly increased. If I were you, I'd just store the reference.
I suggest having a table where you store user data like username, first name. In that table create a field called something like "avatar" in which you can store a file reference.
Assuming your user avatars are stored in: htdocs/images/avatars/
And user apikot has the avatar "avatar.jpg" stored agains it's user in the database, you could then compile the following url when generating an image tag: "/htdocs/images/avatars/avatar.jpg".
Here's an example of storing the image in binary on a MySQL database. I'm not too sure if there are any advantages or not to that. I'll leave it for someone else to comment.
Another way you could do it is store the location of the image in a column and query it for referencing.
Create a BLOB type field, and insert the result of file_get_contents( $ImageFile )
I have built a small web application in PHP where users must first log in. Once they have logged in, I intend on showing a small thumbnail as part of their "profile".
I will have to ensure the image is below a particular size to conserve space, or ensure it is a particular resolution, or both, or even perhaps use something like image magick to scale it down.
Not sure what the best approach for that is yet, any ideas welcome.
Also, I have been trying to work out if it is better to store the image in the users table of MySQL as a blob, or maybe a separate images table with a unique id, and just store the appropriate image id in the users table, or simply save the uploaded file on the server (via an upload page as well) and save the file as theUsersUniqueUsername.jpg.
Best option?
I found a tutorial on saving images to mysql here:
http://www.phpriot.com/articles/images-in-mysql
I am only a hobby programmer, and haven't ever done anything like this before, so examples, and/or a lot of detail is greatly appreciated.
Always depends of context, but usually, I store a user image on the filesystem in a folder called /content/user/{user_id}.jpg and try to bother the database as little as possible.
I would recommend storing the image as a file and then have the file URI in the database. If you store all the images in the database, you might have some problems with scaling at a later date.
Check out this answer too:
Microsoft's advice for SQL Server used to be, for speed and size, store images in the file system, with links in the database. I think they've softened their preference a bit, but I still consider it a better idea certainly for size, since it will take up no space in the database.
The overhead using BLOB is a lot less than most people would have you believe, especially if you set it up right. If you use a separate server just running the DB to store binary files then you can in fact use no file-system at all and avoid any overhead from the file-system
That said the easiest/best way unless you have a couple of servers to yourself is storing them in the filesystem
Do not store the absolute URL of the file in your DB, just the unique part (and possibly a folder or two), e.g. 2009/uniqueImageName.jpg or just uniqueImageName.jpg.
Then in your pages just add the host and other folders onto the front, that way you have some flexibility in moving your images - all you'll need to change is a line or two in your PHP/ASP.NET page.
There is no need to store outside the document root for security - a .htaccess file with DENY FROM ALL will work the same and provide more flexibility
No need to 'shunt' images so much for security, just have a getImage.php page or something, and then instead of inserting the actual URL in the src of the image, use something like getImage.php?file=uniqueImageName.jpg.
Then the getImage.php file can check if the user is authorised and grab the image (or not).
Use a name which is guaranteed to be unique (preferably an integer i.e. primary key) when storing, some file-system (i.e. Windows) are case-insensitive, so JoeBloggs.jpg and joebloggs.jpg are unique for the database, but not for the file-system so one will overwrite another.
Use a separate table for the images, and store the primary key of the image in the users table. If you ever want to add more fields or make changes in future it will be easier - it's also good practice.
If you are worried about SEO and things like that, store the image's original file name in another field when you are uploading, you can then use this in your output (such as in the alt tag).
Challenging the Conventional Wisdom!
Of course it is context dependent, but I have a very large application with thousands of images and documents stored as BLOBS in a MySQL database (average size=2MB) and the application runs fine on a server with 256MB of memory. The secret is correct database structure. Always keep two separate tables, one of which stores the basic information about the file, and the other table should just contain the blob plus a primary key for accessing it. All basic queries will be run against the details table, and the other table is only access when the file is actually needed, and it is accessed using an indexed key so performance is extremely good.
The advantages of storing files in the database are multiple:
Much easier backup systems are required, as you do not need to back up the file system
Controlling file security is much easier as you can validate before releasing the binary (yes, you can store the file in a non-public directory and have a script read and regurgitate the file, but performance will not be noticeably faster.
(Similar to #1) It cleanly separates "user content" and "system content", making migrations and cloning easier.
Easier to manage files, track/store version changes, etc, as you need fewer script modifications to add version controls in.
If performance is a big issue and security and backups aren't (or if you have a good fs backup system) then you can store it the the FS, but even then I often store files (in the case of images) in the DB and building a caching script that writes the image to a cache folder after the first time it's used (yes, this uses more HD space, but that is almost never a limiting factor).
Anyway, obviously FS works well in many instances, but I personally find DB management much easier and more flexible, and if written well the performance penalties are extremely small.
We created a shop that stored images in the DB. It worked great during development but once we tested it on the production servers the page load time was far too high, and it added unneccessary load to the DB servers.
While it seems attractive to store binary files in the DB, fetching and manipulating them adds extra complexity that can be avoided by just keeping files on the file system and storing paths / metadata in the DB.
This is one of those eternal debates, with excellent arguments on both sides, but for my money I would keep images away from the DB.
I recently saw this tip's list: http://www.ajaxline.com/32-tips-to-speed-up-your-mysql-queries
Tip 17:
For your web application, images and other binary assets should normally be stored as files. That is, store only a reference to the file rather than the file itself in the database.
So just save the file path to the image :)
I have implemented both solutions (file system and database-persisted images) in previous projects. In my opinion, you should store images in your database. Here's why:
File system storage is more complicated when your app servers are clustered. You have to have shared storage. Even if your current environment is not clustered, this makes it more difficult to scale up when you need to.
You should be using a CDN for your static content anyways, and set your app up as the origin. This means that your app will only be hit once for a given image, then it will be cached on the CDN. CloudFront is dirt cheap and simple to set up...there's no reason not to use it. Save your bandwidth for your dynamic content.
It's much quicker (and thus cheaper) to develop database persisted images
You get referential integrity with database persisted images. If you're storing images on the file system, you will inevitably have orphan files with no matching database records, or you'll have database records with broken file links. This WILL happen...it's just a matter of time. You'll have to write something to clean these up.
Anyways, my two cents.
What's the blob datatype for anyway, if not for storing files?
If your application involves authorisation prior to accessing the files, the changes are that you're a) storing the files outside of DOCUMENT_ROOT (so they can't be accessed directly; and possibly b) sending the entire contents of the files through the application (of course, maybe you're doing some sort of temporarilly-move-to-hashed-but-publicly-accessible-filename thing). So the memory overhead is there anyway, and you might as well be retrieving the data from the database.
If you must store files in a filesystem, do as Andreas suggested above, and name them using something you already know (i.e. the primary key of the relevant table).
I think that most database engines are so advanced already that storing BLOB's of data does not produce any disadvantages (bloated db etc). One advantage is that you don't have any broken links when the image is in the database already. That being said, I have myself always done so that I store the file on disk and give the URI to the database. It depends on the usage. It may be easier to handle img-in-db if the page is very dynamic and changes often - no namespace -problems. I have to say that it ends down to what you prefer.
I would suggest you do not store the image in your db. Instead since every user will be having a unique id associated with his/her profile in the db, use that id to store the image physically on the server.
e.g. if a user has id 23, you can store an image in www.yourname.com/users/profile_images/23.jpg. Then to display, you can check if the image exists, and display it accordingly else display your generic icon.
As the others suggested:
Store the images in the filesystem
Do not bother to store the filename, just use the user id (or anything else that "you already know")
Put static data on a different server (even if you just use "static.yourdomain.com" as an alias to your normal server)
Why ?
The bigger your database gets the slower it will get.
Storing your image in the database will increase your database size.
Storing the filename will increase your database size.
Putting static data on a different server (alias):
Makes scaling up a lot easier
Most browsers will not send more than two requests to the same server, by putting static data on a "second" server you speed up the loading
After researching for days, I made a system storing images and binaries on the database.
It was just great. I have now 100% control over the files, like access control, image sizing (I don't scale the images dynamically, of course), statistics, backup and maintenance.
In my speed tests, the sistem is now 10x slower. However, it's still not in production and I will implement system cache and other optimizations.
Check this real example, still in development, on a SHARED host, using a MVC:
http://www.gt8.com.br/salaodocalcado/calcados/meia-pata/
In this example, if a user is logged, he can see different images. All products images and others binaries are in DB, not cached, not in FS.
I have made some tests in a dedicated server and results were so far beyond the expectations.
So, in my personal opinion, although it needs a major effort to achieve it, storing images in DB is worth and the benefits are worth much more the cons.
As everybody else told you, never store images in a database.
A filesystem is used to store files -> images are files -> store them in filesystem :-)
Just tested my img's as blob, so. This solution working slower than images on server as file. Loading time should be same with images from DB or http but is't. Why? Im sure, when images are files on server, browser can caching it and loading only once, first time. When image going form DB, every time is loaded again. That's my oppinion. Maybe Im wrong about browser caching, but working slower (blob). Sry my English, whatever ;P
These are the pros of both solutions
In BLOBS :
1) pros : the easiness to mange clusters since you do not have to handle tricky points like file syncs between servers
2) DB backups will be exhaustive also
In files
1) Native caching handly (and that's the missing point of previous comments, with refresh and headers that you won't have to redesign in DB (DB are not handling last modification time by default)
2) Easiness of resizing later on
3) Easiness of moderation (just go through your folders to check if everything is correct)
For all these reasons and since the two pros of databases are easier to replicate on file system I strongly recommend files !
In my case, i store files in file system. In my images folder i create new folder for each item named based on item id (row from db). And name images in an order starting from 0. So if i have a table named Items like this:
Items
|-----|------|-----|
| ID | Name | Date|
|-----|------|-----|
| 29 | Test1| 2014|
|-----|------|-----|
| 30 | Test2| 2015|
|-----|------|-----|
| 31 | Test3| 2016|
|-----|------|-----|
my images directory looks like something like:
images/
29/
30/
31/
images/29/0.png
images/29/1.jpeg
images/29/2.gif
etc.