I tried using PHP to run 7zip to recursively extract all the zip files that a user had put inside other zip files and then delete the original zip.
The code I used worked except for a larger file (about 7gigs) that had some unusual file types (like hdr and cab files for example) where it did not fully extract the files, made duplicates of some of the ones it did, and then did not delete the original zip. The only thing I saw out of the ordinary about it was that the command prompt I ran the php file from said "Incomplete Extraction". I'm not sure why the extraction and deletion worked for every file but this one.
Any help in understanding this would be greatly appreciated!
Thank you for your time
Here is the code snippet:
$cmd_2 = "FOR /R \"$zip_file_directory\" %I IN (*.zip) DO (7z x \"%I\" -aou -o\"%~dpI\" && del \"%~fI\")";
exec($cmd_2, $out_2, $ret_2);
EDIT
Also it returned a 0 exit code. So again I have no idea what went wrong.
However looking at the $out I can see about 2700 key/value relationships in the array (Example: [2685] => Extracting Client Video\Reviewer\setup.lid)
And at the very end it says "Sub Item Errors: 5" but I can't seem to find a way to find exactly what that means.
EDIT II
I was going through the 2700 lines of code and found a few like this: "[1325] => can not open output file ...." and then has a filename.
Any idea why this is happening so rarely (It looks like these are the 5 errors) out of thousands of lines of extraction?
EDIT III
There is an article here that states that this might be a 7zip issue with firewall, can anyone confirm or deny this?
Related
I use flat files on my website to store account information for my game. But now, gem collecting doesn't work anymore. The filesize of the "accounts.ini" file is 218,750 bytes and the bottom of it looks like this:
[117157336030342728342]
GEMS = 7
[112725622837339591876]
GEMS = "1 4"4"
As you can see, the last line is wrong for some reason. What is causing this? Did I hit the filesize limit?
EDIT: Well, I should have tried it before, but I edited the last line to normal and it started working again. But you're right, I should use a database for such things. I've tried using a database before, but I didn't like it back then, but I guess that's not a good reason not to use it. I was just told that I won't be able to reach the "php.ini" file. I don't think I can find it either. Anyways, I'll switch to a database now, thanks for the advice!
By original I mean the one from the file when it was archived.
I know the info is in the zip archive, because when unzipping the archive in Windows, for example, you get the original files' information (last modification date, creation date, and such).
But when extracting the file with ZipArchive::extractTo, its modification date is set to the time of the extraction (which makes some logic), and I cannot read it anymore.
I've seen bits of code using ZipArchive::getStream and stat() but I still get an "altered" date, not the original one.
Is there any built-in functions set that could help me with this ? (I'm on a web host and cannot install much)
I have made searches on Google, have often ended up here, have made some more searches here, but could not find precisely what I needed. If there already is a thread addressing this, please simply point me to it and close this one.
Thanks in advance for any constructive input :-p
For later use, answer with proper formatting :
$zipTmp = new ZipArchive();
$res = $zipTmp -> open("archive.zip");
$info = $zipTmp -> statname("path/to/file/inside/archive.zip");
echo date("YmdHi", $info["mtime"]);
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.
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';
I'm working on a file based commenting system with in-line comments (only 1 level).
Despite being a newby I've managed to create a system in which users are able to add new comments and use #[NUMBER] to add their reply below another comment.
My file and folder structure looks like this:
/threads/
1/
1.txt
2.txt
3.txt
2/
1.txt
3/
1.txt
2.txt
3.txt
4.txt
The folder in threads has the thread number (used to make a reply) for its name and 1.txt contains the contents of the "mother" post. Every post higher than 1 is a reply.
So I could show the threads in the order which they have been made or show them upside down, but they'll be stuck in that order (I'm using a loop to find folders and then increase or decrease the folder number). Does anybody have any ideas on how I can make threads which get replies to the top of the list?
I thought of an order.txt file which has the thread numbers in a certain order and when a reply gets made to thread X the script should put X at the top of that list (or bottom, easy to inverse).
Suggestions are very much appreciated!
Well, while I don't agree with the wisdom of doing it this particular way, the order text file seems fine enough granted depending how often your updating your threads there may be read/write lock issues.
Another option is to check the modified time for the folders and/or posts. http://php.net/manual/en/function.filemtime.php i believe would be an appropriate function.
In reference to sorting you'd need to use a sorting function. The best ideas i can come up with is when creating your array convert the modified time to a unix timestamp and use that as the array index. May need to invert the array after to show newest first but i would think that would work. I'd suggest using the mktime function in conjunction to produce a nicely formatted date/time and then use that for the index.
An alternative is storing an array within array and doing something like this:
$threadArray = array(
array("thread" => "1", "timemodified" => "12703048849"),
array("thread" => "2", "timemodified" => "12703048842"),
array("thread" => "3", "timemodified" => "12703045349"),
array("thread" => "4", "timemodified" => "12703021449"),
);
function sortByTime($a, $b)
{
return strnatcmp($a['timemodified'], $b['timemodified']);
}
# sort
usort($threadArray, 'sortByTime');
Stick a file in each folder (1, 2, 3, etc...) that contains a line with the time that the thread was last updated (could be when it was posted if it has no replies or the time of the last reply). When it's time to display each thread, look at the time in that file and slot it into the correct position when displayed.
The reason I'd do this over creating an order.txt file is that a single file is:
Easily corrupted, meaning that you'd
lose ALL ordering info.
It is inefficient to read/rewrite a large
file everytime a post is added
You can also stick other data you might want into this text file in each folder. It's kind of like how Windows stores thumbnails in a thumbs.db file for each folder.
Pretty similar to box9, but with a different approach.
In each thread folder, make a file, let's say - random.timestamp.txt ($file = 'random.'.time().'.txt';).
Whenever there are changes within the thread, you rename this file with the new timestamp. When you're displaying threads, fetch each threads timestamp file and align them as you wish (DESC / ASC). Something like that..
I'll probably get down voted for this, but if you're not going for a relational database here, why not make the order information part of the file/folder name? So you could order by metadata that is contained as part of the file/folder name scheme (as you have started to do here) your threads directory would contain a 1_2/ (first thread, second order) 2_1/ (second thread, most recent), 3_0/ (third thread, sticky <--please forgive the feature creep) This would allow you to use the split function to get relevant metadata from the file names.
Final folder structures would vary and change on update, but might look something like this in a snapshot:
/threads/
1_2/
1.txt
2.txt
2_3/
1.txt
2.txt
3.txt
3_1/
1.txt
2.txt