Loading CSV from remote file - php

I am writing the following code from a CSV to get stock data, When I have downloaded the string it is splitting it in the following way
<COMPANY NAME>,<STOCK PRICE>,<STOCK CHANGE>
<COMPANY2 NAME>,<STOCK PRICE2>,<STOCK CHANGE2>
I have tried to split the array by using the /n character using the PHP function explode. However this did not split it properly. Here is my code:
public function getQuotes()
{
$result = array();
$format = $this->format;
$stockString = "";
foreach ($this->stocks as $stock)
{
$stockString = $stockString . $stock . "+";
}
//Remove the last "+"
$stockString = substr($stockString,0,strlen($stockString)-1);
$s = file_get_contents("http://finance.yahoo.com/d/quotes.csv?s=". $stockString . "&f=" . $format . "&e=.csv");
//The splitting is to be done here.
}
}
Thank you in advance

Use file function instead of file_get_contents - it will split the content for you, as php manual says:
Returns the file in an array. Each element of the array corresponds to
a line in the file, with the newline still attached. Upon failure,
file() returns FALSE.
Then you can use str_getcsv for each element of array to get field values.
public function getQuotes()
{
$result = array();
$format = $this->format;
$stockString = "";
foreach ($this->stocks as $stock)
{
$stockString = $stockString . $stock . "+";
}
//Remove the last "+"
$stockString = substr($stockString,0,strlen($stockString)-1);
$s = file("http://finance.yahoo.com/d/quotes.csv?s=". $stockString . "&f=" . $format . "&e=.csv");
foreach($s as $line) {
$values = str_getcsv($line);
}
}

Related

PHP prevent extra empty line when writing text to file

I'm having a small issue regarding a foreach() loop and writing an array to a text file within.
The loop gives me the format in the file that I want but it also adds (as I was told) an unwanted empty line at the end of the file.
Here is my piece of code:
foreach($data_arr as $data => $input)
{ fwrite($fh, $data . ":" . $input . "\n") or die("something went wrong here"); }
Is there a way to prevent this from happening and not add the \n when it reaches the end of the array?
You can do something like this :
$data_array = ['c', 'h', "hf"];
$last = count($data_array) - 1; #size of the array
foreach($data_array as $data => $input)
{
$separator = $data == $last ? "" : "\n"; #if is last, then seperator isn't a back to line
fwrite($fh, $data . ":" . $input . $separator);
}
Just check if current index is the last one, then eventually add "\n" to the string
$last_index = count($data_arr)-1;
foreach ($data_arr as $data => $input)
{
$string = $data . ":" . $input;
if ($data != $last_index)
{
$string .= "\n";
}
fwrite($fh, $string) or die("something went wrong here");
}
Determining whether you are doing something for the last time, is cumbersome - for starters, you need to count your items, and then you need a loop index to compare to that count …
Much easier to determine, whether you are doing something for the first time. So just reverse your logic here - do not try to output “all lines, followed by a newline each, except the last one”, but instead, output “all lines preceded by a newline each, except the first one.”
You could use a simple boolean flag for that:
$is_first_line = true;
foreach($data_arr as $data => $input) {
fwrite($fh, ($is_first_line ? "" : "\n") . $data . ":" . $input);
$is_first_line = false;
}
Or you just append a variable before the line data all the time - and simply make that variable “empty” on the first iteration, and then fill it with a newline character for all the following ones:
$prefix = "";
foreach($data_arr as $data => $input) {
fwrite($fh, $prefix . $data . ":" . $input);
$prefix = "\n";
}

PHP - Searching words in a .txt file

I have just learnt some basic skill for html and php and I hope someone could help me .
I had created a html file(a.html) with a form which allow students to input their name, student id, class, and class number .
Then, I created a php file(a.php) to saved the information from a.html into the info.txt file in the following format:
name1,id1,classA,1
name2,id2,classB,24
name3,id3,classA,15
and so on (The above part have been completed with no problem) .
After that I have created another html file(b.html), which require user to enter their name and id in the form.
For example, if the user input name2 and id2 in the form, then the php file(b.php) will print the result:
Class: classB
Class Number: 24
I have no idea on how to match both name and id at the same time in the txt file and return the result in b.php
example data:
name1,id1,classA,1
name2,id2,classB,24
name3,id3,classA,15
<?php
$name2 = $_POST['name2'];
$id2 = $_POST['id2'];
$data = file_get_contents('info.txt');
if($name2!='')
$konum = strpos($data, $name2);
elseif($id2!='')
$konum = strpos($data, $id2);
if($konum!==false){
$end = strpos($data, "\n", $konum);
$start = strrpos($data, "\n", (0-$end));
$row_string = substr($data, $start, ($end - $start));
$row = explode(",",$row_string);
echo 'Class : '.$row[2].'<br />';
echo 'Number : '.$row[3].'<br />';
}
?>
Iterate through lines until you find your match. Example:
<?php
$csv=<<<CSV
John,1,A
Jane,2,B
Joe,3,C
CSV;
$data = array_map('str_getcsv', explode("\n", $csv));
$get_name = function($number, $letter) use ($data) {
foreach($data as $row)
if($row[1] == $number && $row[2] == $letter)
return $row[0];
};
echo $get_name('3', 'C');
Output:
Joe
You could use some simple regex. For example:
<?php
$search_name = (isset($_POST['name'])) ? $_POST['name'] : exit('Name input required.');
$search_id = (isset($_POST['id'])) ? $_POST['id'] : exit('ID input required.');
// First we load the data of info.txt
$data = file_get_contents('info.txt');
// Then we create a array of lines
$lines = preg_split('#\\n#', $data);
// Now we can loop the lines
foreach($lines as $line){
// Now we split the line into parts using the , seperator
$line_parts = preg_split('#\,#', $line);
// $line_parts[0] contains the name, $line_parts[1] contains the id
if($line_parts[0] == $search_name && $line_parts[1] == $search_id){
echo 'Class: '.$line_parts[2].'<br>';
echo 'Class Number: '.$line_parts[3];
// No need to execute the script any further.
break;
}
}
You can run this. I think it is what you need. Also if you use post you can change get to post.
<?php
$name = $_GET['name'];
$id = $_GET['id'];
$students = fopen('info.txt', 'r');
echo "<pre>";
// read each line of the file one by one
while( $student = fgets($students) ) {
// split the file and create an array using the ',' delimiter
$student_attrs = explode(',',$student);
// first element of the array is the user name and second the id
if($student_attrs[0]==$name && $student_attrs[1]==$id){
$result = $student_attrs;
// stop the loop when it is found
break;
}
}
fclose($students);
echo "Class: ".$result[2]."\n";
echo "Class Number: ".$result[3]."\n";
echo "</pre>";
strpos can help you find a match in your file. This script assumes you used line feed characters to separate the lines in your text file, and that each name/id pairing is unique in the file.
if ($_POST) {
$str = $_POST["name"] . "," . $_POST["id"];
$file = file_get_contents("info.txt");
$data = explode("\n", $file);
$result = array();
$length = count($data);
$i = 0;
do {
$match = strpos($data[$i], $str, 0);
if ($match === 0) {
$result = explode(",", $data[$i]);
}
} while (!$result && (++$i < $length));
if ($result) {
print "Class: " . $result[2] . "<br />" . "Class Number: " . $result[3];
} else {
print "Not found";
}
}

Php simple algorithm for autoloader

Here's my "simple" algorithm:
if the class is named like 'AaaBbbCccDddEeeFff' loop like this:
include/aaa/bbb/ccc/ddd/eee/fff.php
include/aaa/bbb/ccc/ddd/eee_fff.php
include/aaa/bbb/ccc/ddd_eee_fff.php
include/aaa/bbb/ccc_ddd_eee_fff.php
include/aaa/bbb_ccc_ddd_eee_fff.php
include/aaa_bbb_ccc_ddd_eee_fff.php
if still nothing found, try to look if those files exist:
include/aaa/bbb/ccc/ddd/eee/fff/base.php
include/aaa/bbb/ccc/ddd/eee/base.php
include/aaa/bbb/ccc/ddd/base.php
include/aaa/bbb/ccc/base.php
include/aaa/bbb/base.php
include/aaa/base.php
include/base.php
If still not found then error.
I'm looking for a fast and easy way to convert this:
'AaaBbbCccDddEeeFff'
to this:
include/aaa/bbb/ccc/ddd/eee/fff.php
and then and easy way to remove latest folder (I guess I should look for explode()).
Any idea how to do this? (I'm not asking for the whole code, I'm not lazy).
Since you specifically asked not to have the whole code, here is some code to get you started. This takes the input and divides it into chunks delineated by changes in case. The rest you can work out as an exercise.
<?php
$input = "AaaBbbCccDddEeeFff";
$str_so_far = "";
$last_was_upper = 0;
$chunks = array();
while($next_letter = substr($input,0,1)) {
$is_upper = (strtoupper($next_letter)==$next_letter);
if($str_so_far && $is_upper && !$last_was_upper) {
$chunks[] = $str_so_far;
$str_so_far = "";
}
if($str_so_far && !$is_upper && $last_was_upper) {
$chunks[] = $str_so_far;
$str_so_far = "";
}
$str_so_far .= $next_letter;
$input = substr($input,1);
$last_was_upper = $is_upper;
}
var_dump($chunks);
?>
I think a regular expression would work. Something like preg_match_all('[A-Z][a-z][a-z]'
, $string); might work - that would match a capital letter, followed by a lowercase letter, and another lowercase letter.
As the other answers are regex, here's a non-regex way for completeness:
function transform($str){
$arr = array();
$part = '';
for($i=0; $i<strlen($str); $i++){
$char = substr($str, $i, 1);
if(ctype_upper($char) && $i > 0){
$arr[] = $part;
$part = '';
}
$part .= $char;
}
$arr[] = $part;
return 'include/' . strtolower(implode('/', $arr)) . '.php';
}
echo transform('AaaBbbCccDddEeeFff');
// include/aaa/bbb/ccc/ddd/eee/fff.php
This builds an array of the folders, so you can manipulate it as needed, for example remove a folder by unsetting the desired index, before it gets imploded.
Here is the first part of your algorithm:
AaaBbbCccDddEeeFff -> include/aaa/bbb/ccc/ddd/eee/fff.php
include/aaa/bbb/ccc/ddd/eee_fff.php
include/aaa/bbb/ccc/ddd_eee_fff.php
include/aaa/bbb/ccc_ddd_eee_fff.php
include/aaa/bbb_ccc_ddd_eee_fff.php
include/aaa_bbb_ccc_ddd_eee_fff.php
I think you can do last part independently based on my answer.
<?php
function convertClassToPath($class) {
return strtolower(preg_replace('/([a-z])([A-Z])/', '$1' . DIRECTORY_SEPARATOR . '$2', $class)) . '.php';
}
function autoload($path) {
$base_dir = 'include' . DIRECTORY_SEPARATOR;
$real_path = $base_dir . $path;
var_dump('Checking: ' . $real_path);
if (file_exists($real_path) === true) {
var_dump('Status: Success');
include $real_path;
} else {
var_dump('Status: Fail');
$last_separator_pos = strrpos($path, DIRECTORY_SEPARATOR);
if ($last_separator_pos === false) {
return;
} else {
$path = substr_replace($path, '_', $last_separator_pos, 1);
autoload($path);
}
}
}
$class = 'AaaBbbCccDddEeeFff';
var_dump(autoload(convertClassToPath($class)));

PHP issue reading huge data from txt files

I'm running a php script that reads from some pipe-delimited txt files, those files contain around 22,000 records. I'm using PHP file() function to read those files, BTW the files have some inter-relation too, I'm pasting the code here for better understanding
public function getGames()
{
$resource = self::DATAFILES.'Product.txt';
$games = array_slice($this->readFile($resource), 1);
$data = array();
$count = 1;
foreach($games as &$records)
{
$game = new Game();
$attributes = explode($this->delimiter,$records);
$game->api = (int) $attributes[0];
$game->console_id = (string) $attributes[1];
$game->title = (string) $this->getTitle($attributes[2]);
$game->barcode = (string) $attributes[4];
$game->image = $this->getCoverImage($attributes[0]);
$game->releateDate = strtotime($attributes[8]);
$data[] = $game;
//if($count == 100): break; else: $count++; endif;
}
print '<pre>'; print_r($data);
}
public function getTitle($titleID)
{
$resource = self::DATAFILES.'Title.txt';
$titles = array_slice($this->readFile($resource), 1);
foreach($titles as $records)
{
$attributes = explode($this->delimiter,$records);
$pattern = '/^' . preg_quote($attributes[0], '/') . '$/';
if (preg_match($pattern, $titleID))
{
return $attributes[2];
break;
}
}
}
public function getCoverImage($gameID)
{
$resource1 = self::DATAFILES.'ProductImage.txt';
$coverImages = array_slice($this->readFile($resource1), 1);
foreach($coverImages as $img_records)
{
$image_attributes = explode($this->delimiter,$img_records);
$pattern1 = '/^' . preg_quote($image_attributes[0], '/') . '$/';
$pattern2 = '/^' . preg_quote($image_attributes[3], '/') . '$/';
if (preg_match($pattern1, $gameID) && preg_match($pattern2, 'Cover'))
{
return $image_attributes[2];
break;
}
}
So the problem I'm facing here is that - when I run that script it will just go on and on nothing happens i.e never throws any error neither print the returned array, however when I limit's the loop iteration up to 100 it works which means nothing wrong with the code so I thought perhaps, php script execution time making trouble so I changed it to max_execution_time = 0 - but still not getting the results. Any help or suggestion, would love hear that.. :)
BTW I'm using Xampp Apache for my local dev !

Function for each subfolder in PHP

I am new in PHP and can't figure out how to do this:
$link = 'http://www.domainname.com/folder1/folder2/folder3/folder4';
$domain_and_slash = http://www.domainname.com . '/';
$address_without_site_url = str_replace($domain_and_slash, '', $link);
foreach ($folder_adress) {
// function here for example
echo $folder_adress;
}
I can't figure out how to get the $folder_adress.
In the case above I want the function to echo these four:
folder1
folder1/folder2
folder1/folder2/folder3
folder1/folder2/folder3/folder4
The $link will have different amount of subfolders...
This gets you there. Some things you might explore more: explode, parse_url, trim. Taking a look at the docs of there functions gets you a better understanding how to handle url's and how the code below works.
$link = 'http://www.domainname.com/folder1/folder2/folder3/folder4';
$parts = parse_url($link);
$pathParts = explode('/', trim($parts['path'], '/'));
$buffer = "";
foreach ($pathParts as $part) {
$buffer .= $part.'/';
echo $buffer . PHP_EOL;
}
/*
Output:
folder1/
folder1/folder2/
folder1/folder2/folder3/
folder1/folder2/folder3/folder4/
*/
You should have a look on explode() function
array explode ( string $delimiter , string $string [, int $limit ] )
Returns an array of strings, each of
which is a substring of string formed
by splitting it on boundaries formed
by the string delimiter.
Use / as the delimiter.
This is what you are looking for:
$link = 'http://www.domainname.com/folder1/folder2/folder3/folder4';
$domain_and_slash = 'http://www.domainname.com' . '/';
$address_without_site_url = str_replace($domain_and_slash, '', $link);
// this splits the string into an array
$address_without_site_url_array = explode('/', $address_without_site_url);
$folder_adress = '';
// now we loop through the array we have and append each item to the string $folder_adress
foreach ($address_without_site_url_array as $item) {
// function here for example
$folder_adress .= $item.'/';
echo $folder_adress;
}
Hope that helps.
Try this:
$parts = explode("/", "folder1/folder2/folder3/folder4");
$base = "";
for($i=0;$i<count($parts);$i++){
$base .= ($base ? "/" : "") . $parts[$i];
echo $base . "<br/>";
}
I would use preg_match() for regular expression method:
$m = preg_match('%http://([.+?])/([.+?])/([.+?])/([.+?])/([.+?])/?%',$link)
// $m[1]: domain.ext
// $m[2]: folder1
// $m[3]: folder2
// $m[4]: folder3
// $m[5]: folder4
1) List approach: use split to get an array of folders, then concatenate them in a loop.
2) String approach: use strpos with an offset parameter which changes from 0 to 1 + last position where a slash was found, then use substr to extract the part of the folder string.
EDIT:
<?php
$folders = 'folder1/folder2/folder3/folder4';
function fn($folder) {
echo $folder, "\n";
}
echo "\narray approach\n";
$folder_array = split('/', $folders);
foreach ($folder_array as $folder) {
if ($result != '')
$result .= '/';
$result .= $folder;
fn($result);
}
echo "\nstring approach\n";
$pos = 0;
while ($pos = strpos($folders, '/', $pos)) {
fn(substr($folders, 0, $pos++));
}
fn($folders);
?>
If I had time, I could do a cleaner job. But this works and gets across come ideas: http://codepad.org/ITJVCccT
Use parse_url, trim, explode, array_pop, and implode

Categories