Problem:
I have a zip file that contains 13 xml files. Each file, except for the first one, contain a quiz question and several answers. When I upload the file to the below script it prints out the questions and the answers correctly, but NOT in order. The order of questions randomly shift each time I upload the zip-file.
Question:
Is there a way I can utilize the file names to tell the script to print out the questions in sequential order every time?
Zip-file contain:
imsmanifest.xml
item101008.xml
item101009.xml
item101010.xml
item101011.xml
item101012.xml
item101013.xml
item101014.xml
item101015.xml
item101016.xml
item101017.xml
item101018.xml
item101019.xml
PHP-script (warning, long script):
<?php
//Initialize counter
$i = 0;
//Go through each file
while (($file = readdir($dh)) !== false)
{
//Skipt the first loop
if ($i > 1)
{
//Ignore misc file
if ($file != 'imsmanifest.xml')
{
//Create new DOM document
$dom= new DOMDocument();
//Load XML file
$dom->load('uploads/' . $file);
//Do not preserve white space
$dom->preserveWhiteSpace = false;
//Check if correct answers should be displayed
if (isset($_POST['XMLAnswers']))
{
//Get correct answer
$correct = $dom->getElementsByTagName( "correctResponse" )->item(0)->nodeValue;
//Get question
$questions = $dom->getElementsByTagName('p')->item(0)->nodeValue;
//Print out question
echo '<h4>' . htmlspecialchars($questions) . '</h4>' . "\n";
//Get answers
$domTable = $dom->getElementsByTagName("simpleChoice");
//Loop through each answer
foreach ($domTable as $answers)
{
//Delete potential unnecessary tags
$pattern = array(
'<p xmlns="http://www.imsglobal.org/xsd/imsqti_v2p1">',
'</p>'
);
//Check if answer is correct one
if ($correct == $answers->getAttribute('identifier'))
{
//Print out correct answer
echo '<span style="color:red;">' . utf8_decode(str_replace($pattern, '', innerHTML($answers))) . '</span><br />' . "\n";
}
else
{
//Print out answer
echo utf8_decode(str_replace($pattern, '', innerHTML($answers))) . '<br />' . "\n";
}
}
}
}
}
//Increment counter
$i++;
}
?>
Rather than using opendir/readdir, use scandir. See http://www.php.net/manual/en/function.scandir.php. scandir returns you a sorted array of files in the directory. You should be able to drop this in and have your code work with minimal changes, other than replacing the outer while readdir loop with:
$files = scandir($dir);
foreach ($files as $file) {
//your current code
}
Related
I'm trying to create a PHP menu which displays the directories and files in each directory in a list, with links to each file in those directories (but not links to the directories themselves). The directories are numerical as years '2013', '2014', etc., and the files in these directories are PDFs.
In essence:
--- 2013 (not linked)
--------------- 01.pdf (linked)
--------------- 02.pdf (linked)
--------------- 03.pdf (linked)
--- 2014 (not linked)
--------------- 04.pdf (linked)
--------------- 05.pdf (linked)
--------------- 06.pdf (linked)
Currently, my code looks like this:
<?php
function read_dir_content($parent_dir, $depth = 0){
if ($handle = opendir($parent_dir))
{
while (false !== ($file = readdir($handle)))
{
if(in_array($file, array('.', '..'))) continue;
if( is_dir($parent_dir . "/" . $file) ){
$str_result .= "<li>" . read_dir_content($parent_dir . "/" . $file, $depth++) . "</li>";
}
$str_result .= "<li><a href='prs/{$file}'>{$file}</a></li>";
}
closedir($handle);
}
$str_result .= "</ul>";
return $str_result;
}
echo "<ul>".read_dir_content("prs/")."</ul>";
?>
However, this creates a complete mess when processed. (Unfortunately I cannot post an image as I am a new user, but if it's not too taboo, I will provide a sneaky link to it: http://i.stack.imgur.com/gmIFz.png)
My questions/requests for help on:
1. Why is the order reversed alphanumerically, i.e. why is 2013 at the bottom of the list and 2014 at the top?
2. How can I remove the links for the directories while keeping the links for the PDFs?
3. I'm confused over why there are empty list items at the end of each directory's list and why they are not logically/consistently spaced, i.e. why are the 01, 02, 03 PDFs not subordinate to the 2013 (see 'in essence' spacing above)?
N.B. I am new to programming and PHP, so please bear in mind that my obvious mistake/s might be very simple. Sorry in advance if they are.
edit: what would also be a massive bonus would be to get rid of the ".pdf"s on the end of the filenames, but that is probably an entirely different question/matter.
PHP5 has class called RecursiveDirectoryIterator
This code :
Sorts the list as you want (2013 first then 2014)
Does not show the links to the directories
Solves the formatting troubles
BONUS: removes the pdf extension
..
$myLinks = array();
$dirIterator = new RecursiveDirectoryIterator($parent_dir);
//iterates main prs directory
foreach ($dirIterator as $file) {
// If its a directory, it will iterate it's children (except if it's . or ..)
if ($file->isDir() && $file->getFilename() != '.' && $file->getFilename() != '..') {
$dir = new RecursiveDirectoryIterator($file->getRealPath());
$myLinks[$file->getFilename()] = array();
foreach ($dir as $subFile) {
//If it finds a file whose extension is pdf
if ($subFile->isFile() && $subFile->getExtension() == 'pdf') {
// Gets its filename and removes extension
$fname = str_replace('.pdf', '', $subFile->getFilename());
// adds the file information to an array
$myLinks[$file->getFilename()][$fname] = "prs/{$file->getFilename()}/{$subFile->getFilename()}";
}
}
}
}
//Sort our array alphabetically (and numerically) and recursively
ksort_recursive($myLinks);
function ksort_recursive(&$array)
{
if (!is_array($array)) return;
ksort($array);
foreach ($array as $k=>$v) {
ksort_recursive($array[$k]);
}
}
// now we print our links as a unordered list
print '<ul>';
foreach ($myLinks as $year => $val) {
print "<li>$year";
foreach ($val as $name => $link) {
print "<li><a href='$link'>$name</a></li>";
}
print '</li>';
}
print '</ul>';
First off I see this line in there
$str_result .= "</ul>";
but I don't see an opening ul tag. This is probably the source of the crazy looking result.
1) I would use scandir instead of readdir as it would let you set the sort order.
2,3) Get rid of $str_result .= "</ul>"; and try something like this in your inside your while loop to remove the dir links and get the order right: (NOTE: I have not run this)
if( ! in_array($file, array('.', '..')) ) {
if( is_dir($parent_dir . "/" . $file) ){
$str_result .= "<li>{$file}</li>";
$str_result .= "<ul>";
$str_result .= "<li>" . read_dir_content($parent_dir . "/" . $file, $depth++) . "</li>";
$str_result .= "</ul>";
} else {
$str_result .= "<li><a href='prs/{$file}'>{$file}</a></li>";
}
}
I have a php code that will display the amount of files that i have in a folder.
Code: This will echo this on my page, "There are a total of 119 Articles"
$directory = "../health/";
if (glob($directory . "*.php") != false) /* change php to the file you require either html php jpg png. */ {
$filecount = count(glob($directory . "*.php")); /* change php to the file you require either html php jpg png. */
echo "<p>There are a total of";
echo " $filecount ";
echo "Articles</p>";
} else {
echo 0;
}
Question:
I am wanting to count the files from 27 or more folders and echo the total amount of files.
Is there away i can add a list of folders to open such as:
$directory = "../health/","../food/","../sport/";
then it will count all the files and display the total "There are a total of 394 Articles"
Thanks
Yes you can:
glob('../{health,food,sport}/*.php', GLOB_BRACE);
Undoubtedly, this is less efficient than clover's answer:
$count = 0;
$dirs = array("../health/","../food/","../sport/");
foreach($dirs as $dir){
if($files = glob($dir."*.php")){
$count += count($files);
}
}
echo "There are a total of $count Articles";
A simple answer is to just use an array and a loop. It is something you could have figured out yourself.
$directories = array('../health/', '../food/', '../sport/');
$count = 0;
foreach ($directories as $dir) {
$files = glob("{$dir}*.php") ?: array();
$count += count($files);
}
echo "<p>There are a total of {$count} articles</p>";
But #clover's answer is better.
As usual, it's often much better to divide your problem. E.g.:
Obtain the files (See glob).
Count the files of a glob result (Write a function that takes care of two the FALSE and Array cases.).
Do the output (don't do the output inside the other code, do it at the end, use variables (as you already do, just separate the output)).
Some Example Code:
/**
* #param array|FALSE $mixed
* #return int
* #throws InvalidArgumentException
*/
function array_count($mixed) {
if (false === $mixed) {
return 0;
}
if (!is_array($mixed)) {
throw new InvalidArgumentException('Parameter must be FALSE or an array.');
}
return count($mixed);
}
$directories = array("health", "food", "string");
$pattern = sprintf('../{%s}/*.php', implode(',', $directories));
$files = glob($pattern, GLOB_BRACE);
$filecount = array_count($files);
echo "<p>There are a total of ", $filecount, " Article(s)</p>";
You could use the opendir command explained here:
http://www.php.net/manual/en/function.opendir.php
combined with the example shown on previous link:
<?php
$dir = "/etc/php5/";
// Open a known directory, and proceed to read its contents
if (is_dir($dir)) {
if ($dh = opendir($dir)) {
while (($file = readdir($dh)) !== false) {
echo "filename: $file : filetype: " . filetype($dir . $file) . "\n";
}
closedir($dh);
}
}
?>
Basically opening the folder you first go through and in a loop count every singel item that is not a folder.
Edit:
Seems like someone has given a simpler solution than this.
Can someone please xplain this code. Im reading larry ullmans book on php and i dont get this part. Thanks in advance!!
$search_dir = '.';
$contents = scandir($search_dir);
print '<h2>Directories</h2>
<ul>';
foreach ($contents as $item) {
if ( (is_dir($search_dir . '/' . $item)) AND (substr($item, 0, 1) != '.') ) {
print "<li>$item</li>\n";
}
}
print '</ul>';
It shows you list of all directories in current directory
I'll repost your code with comments to exaplain what each line does.
$search_dir = '.'; //Set the directory to search. "." means the current one.
$contents = scandir($search_dir); //scan the directory and return its results into $contents
print '<h2>Directories</h2>
<ul>';
foreach($contents as $item) { //Iterate through the array and for each item...
//If the item is a directory AND it doesn't start with a . (which means the current one)...
if ((is_dir($search_dir.'/'.$item)) AND(substr($item, 0, 1) != '.')) {
print "<li>$item</li>\n"; //Print it
}
}
print '</ul>';
In short, it prints out an output of the directories inside the directory the script is running in.
I need to find word count for all of the files within a folder.
Here is the code I've come up with so far:
$f="../mts/sites/default/files/test.doc";
// count words
$numWords = str_word_count($str)/11;
echo "This file have ". $numWords . " words";
This will count the words within a single file, how would I go about counting the words for all files within a given folder?
how about
$array = array( 'file1.txt', 'file2.txt', 'file3.txt' );
$result = array();
foreach($array as $f ){
$result[$f] = str_word_count(file_get_contents($f));
}
and using the dir
if ($handle = opendir('/path/to/files')) {
$result = array();
echo "Directory handle: $handle\n";
echo "Files:\n";
/* This is the correct way to loop over the directory. */
while (false !== ($file = readdir($handle))) {
if($file == '.' || $file == '..')
continue;
$result[$file] = str_word_count(file_get_contents('/path/to/files/' . $file));
echo "This file {$file} have {$result[$file]} words";
}
closedir($handle);
}
Lavanya, you can consult the manual of readdir, file_get_contents.
Assuming the doc files are plaintext and don't contain additional markup, you can use the following script to count all of the words in all of the files:
<?php
$dirname = '/path/to/file/';
$files = glob($dirname.'*');
$total = 0;
foreach($files as $path) {
$count = str_word_count(file_get_contents($path));
print "\n$path has $count words\n";
$total += $count;
}
print "Total words: $total\n\n";
?>
If you are using *nux than you can use system('cat /tmp/* | wc -w')
You can use $words = str_word_count(file_get_contents($filepath)) to get the word count of a text file, however this won't work for word docs. You'll need to find a library or external program that can read the .doc file format.
The XML feed is located at: http://xml.betclick.com/odds_fr.xml
I need a php loop to echo the name of the match, the hour, and the bets options and the odds links.
The function will select and display ONLY the matchs of the day with streaming="1" and the bets type "Ftb_Mr3".
I'm new to xpath and simplexml.
Thanks in advance.
So far I have:
<?php
$xml_str = file_get_contents("http://xml.betclick.com/odds_fr.xml");
$xml = simplexml_load_string($xml_str);
// need xpath magic
$xml->xpath();
// display
?>
Xpath is pretty simple once you get the hang of it
you basically want to get every match tag with a certain attribute
//match[#streaming=1]
will work pefectly, it gets every match tag from underneath the parent tag with the attribute streaming equal to 1
And i just realised you also want matches with a bets type of "Ftb_Mr3"
//match[#streaming=1]/bets/bet[#code="Ftb_Mr3"]
This will return the bet node though, we want the match, which we know is the grandparent
//match[#streaming=1]/bets/bet[#code="Ftb_Mr3"]/../..
the two dots work like they do in file paths, and gets the match.
now to work this into your sample just change the final bit to
// need xpath magic
$nodes = $xml->xpath('//match[#streaming=1]/bets/bet[#code="Ftb_Mr3"]/../..');
foreach($nodes as $node) {
echo $node['name'].'<br/>';
}
to print all the match names.
I don't know how to work xpath really, but if you want to 'loop it', this should get you started:
<?php
$xml = simplexml_load_file("odds_fr.xml");
foreach ($xml->children() as $child)
{
foreach ($child->children() as $child2)
{
foreach ($child2->children() as $child3)
{
foreach($child3->attributes() as $a => $b)
{
echo $a,'="',$b,"\"</br>";
}
}
}
}
?>
That gets you to the 'match' tag which has the 'streaming' attribute. I don't really know what 'matches of the day' are, either, but...
It's basically right out of the w3c reference:
http://www.w3schools.com/PHP/php_ref_simplexml.asp
I am using this on a project. Scraping Beclic odds with:
<?php
$match_csv = fopen('matches.csv', 'w');
$bet_csv = fopen('bets.csv', 'w');
$xml = simplexml_load_file('http://xml.cdn.betclic.com/odds_en.xml');
$bookmaker = 'Betclick';
foreach ($xml as $sport) {
$sport_name = $sport->attributes()->name;
foreach ($sport as $event) {
$event_name = $event->attributes()->name;
foreach ($event as $match) {
$match_name = $match->attributes()->name;
$match_id = $match->attributes()->id;
$match_start_date_str = str_replace('T', ' ', $match->attributes()->start_date);
$match_start_date = strtotime($match_start_date_str);
if (!empty($match->attributes()->live_id)) {
$match_is_live = 1;
} else {
$match_is_live = 0;
}
if ($match->attributes()->streaming == 1) {
$match_is_running = 1;
} else {
$match_is_running = 0;
}
$match_row = $match_id . ',' . $bookmaker . ',' . $sport_name . ',' . $event_name . ',' . $match_name . ',' . $match_start_date . ',' . $match_is_live . ',' . $match_is_running;
fputcsv($match_csv, explode(',', $match_row));
foreach ($match as $bets) {
foreach ($bets as $bet) {
$bet_name = $bet->attributes()->name;
foreach ($bet as $choice) {
// team numbers are surrounded by %, we strip them
$choice_name = str_replace('%', '', $choice->attributes()->name);
// get the float value of odss
$odd = (float)$choice->attributes()->odd;
// concat the row to be put to csv file
$bet_row = $match_id . ',' . $bet_name . ',' . $choice_name . ',' . $odd;
fputcsv($bet_csv, explode(',', $bet_row));
}
}
}
}
}
}
fclose($match_csv);
fclose($bet_csv);
?>
Then loading the csv files into mysql. Running it once a minute, works great so far.