identify lines in a file in php - php

I have a file, which contains passwords/usernames:
thomas 123
john 321
What would be the best way to identify lines and add to them contact information? Right in password file I dont want store, because the size of the file matters.. I thought to add an identifier string before records, like this:
[1]
thomas 123
[2]
john 321
What do you think? It is a good way to identify lines? If yes, how I can read out line after identifier [number]?
If I can read out, then in a second file I can store contact information.
[1]
email, etc
[2]
email etc
this is a config file of an offline app, sadly I cant change the structure of that file (max. change: add an identifier before lines) or use database.
Thank you so much,
Adrian

You could use a while loop that reads every other line as your id and every other line as your username and password; however, like what #zerkms said, you're better off putting your energy into a tried and tested database.
Learning to use a database will save you time in the future so that on each project you don't have to figure out exactly how to manipulate a flat file.
Reusable solutions enable and empower you to focus on your goal and your product, whatever that may be.

As zerkms wrote in his comment to your question, you should probably use a database for that. If you don't feel comfortable with setting up a database on a server, look into SQLite (php manual) which is a file-based database which is really easy to use and setup.
If you want to stick with the text-file approach, why write your own format and parser? You could just as well use an existing format like JSON (can be parsed with json_decode) or even an INI file (use parse_ini_file).
And: Never store your text-file at a place where it's globally accessible (eg. webroot).

Supposedly the usernames in the password file are unique (otherwise it wouldn't be very useful). Assuming that's the case, why can't you leave its structure as is without adding anything to it? Then your contact file could be formatted as an INI file or JSON file as bummzack suggested with the username as the key.

You can handle this as simple as a single call to file function.
$lines = file ('passwords.txt');
After that you'll have all lines numbered from 0 to N-1.

Related

php how to link a file from file server to that info from database

i'm new to PHP, and i'm trying to upload file to file server and file information to mysql database, i have done uploading file server and database part but i need to retrieve the info of specific file from my file server folder if i click that file, i'm trying get that logic. please help me if there is any solid solution for this. (correct me if i'm wrong, my idea was to upload the file path to database along with info, is this will give me solution? but the filename can be duplicate)
I figured I would write a short(for me this is short) "answer" just so I could summarize my points.
Some "Best Practices" when creating a file storage system. File storage is a broad category so your mileage may vary for some of these. Take them just as suggestion of what I found works well.
Filenames
Don't store the file with the name give it by an end user. They can and will use all kind of crappy characters that will make your life miserable. Some can be as bad as ' single quotes, which on linux basically makes it so it's impossible to read, or even delete the file ( directly ). Some things can seem simple like a space but depending on where you use it and the OS on your server you could wind up with one%20two.txt or one+two.txt or one two.txt which may or may not create all kinds of issues in your links.
The best thing to do is create a hash, something like sha1 this can be as simple as {user_id}{orgianl_name} The username make it less likely of collisions with other users filenames.
I prefer doing file_hash('sha1', $contents) that way if someone uploads the same file more then once you can catch that ( the contents are the same the hash is the same). But if you expect to have large files you may want to do some bench marking on it to see what type of performance it has. I mostly handle small files so it works fine for that.
-note- that with the timestamp the file can still be saved because the full name is different, but it makes it quite easy to see, and it can be verified in the database.
Regardless of what you do I would prefix it with a timestamp time().'-'.$filename. This is useful information to have, because its the absolute time the file was created.
As for the name a user give the file. Just store that in the database record. This way you can show them the name they expect, but use a name you know is always safe for links.
$filename = 'some crapy^ fileane.jpg';
$ext = strrchr($filename, '.');
echo "\nExt: {$ext}\n";
$hash = sha1('some crapy^ fileane.jpg');
echo "Hash: {$hash}\n";
$time = time();
echo "Timestamp: {$time}\n";
$hashname = $time.'-'.$hash.$ext;
echo "Hashname: $hashname\n";
Ouputs
Ext: .jpg
Hash: bb9d2c2c7c73bb8248537a701870e35742b41c02
Timestamp: 1511853063
Hashname: 1511853063-bb9d2c2c7c73bb8248537a701870e35742b41c02.jpg
You can try it here
Paths never store the full path to the file. All you need in the database is the hash from creating the hashed name. The "root" path to the folder the file is stored in should be done in PHP. This has several benefits.
prevents directory transferal. Because your not passing any part of the path around you don't have to worry as much about someone slipping a \..\.. in there and going places they shouldn't. A poor example of this would be someone overwriting a .htpassword file by uploading a file named that with directory transverse in it.
Has more uniform looking links, uniform size, uniform set of
characters.
https://en.wikipedia.org/wiki/Directory_traversal_attack
Maintenance. Paths change, Servers change. Demands on your system change. If you need to relocate those files, but you stored the absolute full path to them in the DB your stuck gluing everything together with symlinks or updating all your records.
There are some exceptions to this. If you want to store them in a monthly folder or by username. You could save that part of the path, in a seperate field. But even in that case, you could build it dynamically based on data saved in the record. I have found it's best to save as little path info as possible. And them make a config or a constant you can use in all the places you need to put the path to the file.
Also the path and the link are very different, so by saving only the name you can link it from whatever PHP page you want without having to subtract data from the path. I've always found it easier to add to the filename then to subtract from a path.
Database (just some suggestions, use may vary )
As always with data ask yourself, who, what, where, when
id - int primary key auto increment
user_id - int foreign key, who uploaded it
hash - char[40] *sha1*, unique what the hash
hashname - varchar {timestampl}-{hash}.{ext} where the files name on the hard drive
filename - varchar the original name give by the user, that way we can show them the name they expect ( if that is important )
status - enum[public,private,deleted,pending.. etc] status of the file, depending on your use case, you may have to review the files, or maybe some are private only the user can see them, maybe some are public etc.
status_date - timestamp|datetime time the status was changed.
create_date - timestamp|datetime when time the file was created, a timestamp is prefered as it makes some things easier but it should be the same timestamp use in the hashname, in that case.
type - varchar - mime type, can be useful for setting the mime type when downloading etc.
If you expect different users to upload the same file and you use the file_hash you can make the hash field a combined unique index of the user_id and the hash this way it would only conflict if the same user uploaded the same file. You could also do it based on the timestamp and hash, depending on your needs.
That's the basic stuff I could think of, this isn't an absolute just some fields I thought would be useful.
It's useful to have the hash by itself, if you store it by it's self you can store it in a CHAR(40) for sha1 (takes up less space in the DB then VARCHAR) and set the collation, to UTF8_bin which is binary. This makes searches on it case sensitive. Although there is little possibility of a hash collision, this adds just a bit more protection because hashes are upper an lower case letters.
You can always build the hashname on the fly if you store the extension, and the timestamp separate. If you find yourself creating things time and time again you may just want to store it in the DB to simplify the work in PHP.
I like just putting the hash in the link, no extension no anything so my links look like this.
http://www.example.com/download/ad87109bfff0765f4dd8cf4943b04d16a4070fea
Real simple, real generic, safe in urls always the same size etc..
The hashname for this "file" would be like this
1511848005-ad87109bfff0765f4dd8cf4943b04d16a4070fea.jpg
If you do have conflicts with the same file and different user(which I mentioned above). You can always add the timestamp part into the link, the user_id or both. If you use the user_id, it might be useful to left pad it with zeros. For example some users may have ID:1 and some may be ID:234 so you could left pad it to 4 places and make them 0001 and 0234. Then add that to the hash, which is almost unnoticeable:
1511848005-ad87109bfff0765f4dd8cf4943b04d16a4070fea0234.jpg
The important thing here is that because sha1 is always 40 and the id is always 4 we can separate the two accurately and easily. And this way, you can still look it up uniquely. There are a lot of different options but so much depends on your needs.
Access
Such as downloading. You should always output the file with PHP, don't give them direct access to the file. The best way is to store the files outside of the webroot ( above the public_html, or www folder ). Then in PHP you can set the headers to the correct type ans basically read out the file. This works for pretty much everything except video. I don't handle videos so that's a topic outside of my experience. But I find it best to think of it as all file data is text, its the headers that make that text into an image, or an excel file or a pdf.
The big advantage of not giving them direct access to the file is if you have a membership site, of don't want your content accessible without a login, you can easily check in PHP if they are logged in before giving them the content. And, as the file is outside the webroot, they can't access it any other way.
The most important thing is to pick something consistent, that is still flexible enough to handle all your needs.
I'm sure I can come up with more, but if you have any suggest feel free to comment.
BASIC PROCESS FLOW
User submits form (enctype="multipart/form-data")
https://www.w3schools.com/tags/att_form_enctype.asp
Server receives the post from the form, Super Globals $_POST and the $_FILES
http://php.net/manual/en/reserved.variables.files.php
$_FILES = [
'fieldname' => [
'name' => "MyFile.txt" // (comes from the browser, so treat as tainted)
'type' => "text/plain" // (not sure where it gets this from - assume the browser, so treat as tainted)
'tmp_name' => "/tmp/php/php1h4j1o" // (could be anywhere on your system, depending on your config settings, but the user has no control, so this isn't tainted)
'error' => "0" //UPLOAD_ERR_OK (= 0)
'size' => "123" // (the size in bytes)
]
];
Check for errors if(!$_FILES['fielname']['error'])
Sanitize display name $filename = htmlentities($str, ENT_NOQUOTES, "UTF-8");
Save file, create DB record ( PSUDO-CODE )
Like this:
$path = __DIR__.'/uploads/'; //for exmaple
$time = time();
$hash = hash_file('sha1',$_FILES['fielname']['tmp_name']);
$type = $_FILES['fielname']['type'];
$hashname = $time.'-'.$hash.strrchr($_FILES['fielname']['name'], '.');
$status = 'pending';
if(!move_uploaded_file ($_FILES['fielname']['tmp_name'], $path.$hashname )){
//failed
//do somehing for errors.
die();
}
//store record in db
http://php.net/manual/en/function.move-uploaded-file.php
Create link ( varies based on routing ), the simple way is to do your link like this http://www.example.com/download?file={$hash} but it's uglier then http://www.example.com/download/{$hash}
user clicks link goes to download page.
get INPUT and look up record
$hash = $_GET['file'];
$stmt = $PDO->prepare("SELECT * FROM attachments WHERE hash = :hash LIMIT 1");
$stmt->execute([":hash" => $hash]);
$row = $stmt->fetch(PDO::FETCH_ASSOC);
print_r($row);
http://php.net/manual/en/intro.pdo.php
Etc....
Cheers!

How to parse CSV file in PHP and store fields in a database?

I need help parsing the following a CSV file in PHP, so I can insert the contents into a database.
I know I use file_get_contents() but after that I feel a bit lost.
What I'd like to store.
Collection1 - events.text & date
Collection2 - position & name.text & total
I'm not sure how best structure the data to insert into a database table.
"**collection1**"
"events.href","**events.text**","**date**","index","url"
"tur.com/events/classic.html","John Deere Classic","Thursday Jul 9
- Sunday Jul 12, 2015","1","tur.com/r.html"
"collection2"
"**position**","name.href","**name.text**","**total**","index","url"
"--","javascript:void(0);","Scott","--","2","tur.com/r.html"
"--","javascript:void(0);","Billy","--","3","tur.com/r.html"
"--","javascript:void(0);","Jon","--","4","tur.com/r.html"
"--","javascript:void(0);","Bill","--","5","tur.com/r.html"
"--","javascript:void(0);","Tim","--","6","tur.com/r.html"
"--","javascript:void(0);","Carlos","--","7","tur.com/r.html"
"--","javascript:void(0);","Robert","--","8","tur.com/r.html"
"--","javascript:void(0);","Rod","--","9","tur.com/r.html"
As per your previous question, I think this needs to be broken down into sections. As it stands it is rather too broad to answer.
Read the information using file_get_contents(). Make sure this works first, by echoing it to the console. (It sounded from your other question that you felt this would not work if the URL does not have a .csv suffix. It should work regardless of the file extension - try it. If it fails it may be dependent on cookies or JavaScript or some other problem).
Design and create your table structure in MySQL. It seems like you have two tables. They should both have a primary key. Are they related in some fashion? If so, perhaps one has a foreign key to the other one?
Explode your text file on the new line character and loop across the resulting array of lines.
If your CSV data has a title row in the first row position, delete that from your array.
For each line, read the elements of interest using PHP's build-in CSV parsing functions, and store them in variables.
Pass these variables to a custom function that saves the data.
For each save, you'll need to do an INSERT. I recommend using PDO here. Make sure you bind your parameters.
Where you get stuck on a specific problem, you can ask a new and focussed question. At present, the task is to break things down into discrete and researchable pieces.
One trick worth remembering is this shortcut to the PHP manual. If you do not know how fgetcsv works, for example, type php.net/fgetcsv into your browser address bar, and the PHP site will find the function for you. The documentation is excellent.

fopen and write in file

I have some questions about fopen
The first question it’s when i go for add new entry always put to the end of file and no start the file, for example:
$fp=fopen("text.dat","a");
fputs($fp,"Hello 1"."\n");
fclose($fp);
Always the results in this file show to the end:
Hello 1
Hello 2
Hello 3
And no as I want, insert the new comment to the first place for show this as:
Hello 3
Hello 2
Hello 1 ( The most old entry )
By other side my second question, for example if i have 10 users and this 10 users to the same time insert one entry or post inside this text file, it’s possible or can give me some error? Or I need use flock until save each post, which it’s the best method for no give me problems when some users want change something in the file in the same time?
There's no way to prepend the file automatically. So, it is better to store the existing contents in a temp file and then insert it in the file.
$fp=fopen("text.dat","w");
fwrite($fp,"Hello 1"."\n".fread($fp));
fclose($fp);
This will be outputting as:
Hello 3
Hello 2
Hello 1
But as far as lock is considered, I don't think it is possible, or am not the right person to answer for this.
When you write to a file it'll always append at the end. There's no workaround it which I'm aware of, but in order to achieve what you want (which is to display the lines in reverse order) you can read the lines into an array and display the array in reverse order.
As for locking, only one process can hold the lock to a file, so you don't really have to do anything cause if two users try to update the same file at the same time - only one of them will succeed - which actually creates a different problem (one of the users will lose her post). In order to work around it you should send to the backend both the original copy of the post and the new version submitted by the user, before you save the user's edit - check that the original version is updated. If it's not up-to-date it means that another user changed it meanwhile. The "user-friendly" behavior would be to return an error to the user saying that he's version is not up-to-date but also include his edits - so that he won't have to re-write everything from scratch.
For that you need a database, which is more suited for multi-user things and sorting,
Or else use a subdirectory and create every message in its own file, with a file name made up of a sortable timestamp: yyyymmddhhmmss. But then you need to prevent directory caching.
As everyone has the right to be stubborn/cut of an edge: see file_get_contents to load all the contents, and file_put_contents.

Using PHP to replace a line in a flat-file database

There are quite a few different threads about this similar topic, yet I have not been able to fully comprehend a solution to my problem.
What I'd like to do is quite simple, I have a flat-file db, with data stored like this -
$username:$worldLocation:$resources
The issue is I would like to have a submit data html page that would update this line based upon a search of the term using php
search db for - $worldLocation
if $worldLocation found
replace entire line with $username:$worldLocation:$updatedResources
I know there should be a fairly easy way to get this done but I am unable to figure it out at the moment, I will keep trying as this post is up but if you know a way that I could use I would greatly appreciate the help.
Thank you
I always loved c, and functions that came into php from c.
Check out fscanf and fprintf.
These will make your life easier while reading writing in a format. Like say:
$filehandle = fopen("file.txt", "c");
while($values = fscanf($filehandle, "%s\t%s\t%s\n")){
list($a, $b, $c) = $values;
// do something with a,b,c
}
Also, there is no performance workaround for avoiding reading the entire file into memory -> changing one line -> writing the entire file. You have to do it.
This is as efficient as you can get. Because you most probably using native c code since I read some where that php just wraps c's functions in these cases.
You like the hard way so be it....
Make each line the same length. Add space, tab, capital X etc to fill in the blanks
When you want to replace the line, find it and as each line is of a fixed length you can replace it.
For speed and less hassle use a database (even SQLLite)
If you're committed to the flat file, the simplest thing is iterating through each line, writing a new file & changing the one that matches.
Yeah, it sucks.
I'd strongly recommend switching over to a 'proper' database. If you're concerned about resources or the complexity of running a server, you can look into SQLite or Berkeley DB. Both of these use a database that is 'just a file', removing the issue of installing and maintaining a DB server, but still you the ability to quickly & easily search, replace and delete individual records. If you still need the flat file for some other reason, you can easily write some import/export routines.
Another interesting possibility, if you want to be creative, would be to look at your filesystem as a database. Give each user a directory. In each directory, have a file for locations. In each file, update the resources. This means that, to insert a row, you just write to a new file. To update a file, you just rewrite a single file. Deleting a user is just nuking a directory. Sure, there's a bit more overhead in slurping the whole thing into memory.
Other ways of solving the problem might be to make your flat-file write-only, since appending to the end of a file is a trivial operation. You then create a second file that lists "dead" line numbers that should be ignored when reading the flat file. Similarly, you could easily "X" out the existing lines (which, again, is far easier than trying to update lines in a file that might not be the same length) and append your new data to the end.
Those second two ideas aren't really meant to be practical solutions as much as they are to show you that there's always more than one way to solve a problem.
ok.... after a few hours work..this example woorked fine for me...
I intended to code an editing tool...and use it for password update..and it did the
trick!
Not only does this page send and email to user (sorry...address harcoded to avoid
posting aditional code) with new password...but it also edits entry for thew user
and re-writes all file info in new file...
when done, it obviously swaps filenames, storing old file as usuarios_old.txt.
grab the code here (sorry stackoverflow got VERY picky about code posting)
https://www.iot-argentina.xyz/edit_flat_databse.txt
Is that what you are location for :
update `field` from `table` set `field to replace` = '$username:$worldlocation:$updatesResources' where `field` = '$worldLocation';

Redirect post without database

I want to get content of a textbox posted on other page without database, means m creating a complaint box, and complaint should be posted on admin page. Every new complain should b at top and others below it. can you please help.
When you store some data, you are creating Data-Base as well
If you don't want to use SQL or similar (liteSQL, XML file DB,...)
you can use directory structure like this
/[year]
/[year]/[month]
/[year]/[month]/[day]
/[year]/[month]/[day]/[exact_timestamp]+[random_hash].[file_extension]
and save them in file structure, each complain as standalone text file
It may be best to just have one, delimited file. Then you only have to read from one place. Depending on the frequency of your complaints, you may want to have one file per day.
To avoid strange locking issues maybe do something similar to what Marek suggested and temporarily store each complaint in a standalone file. Then run a CRON to concatenate them every so often

Categories