Why is my first value in reset() null? - php

I have a server with a directory full of books. I wrote a script which loops through this directory and lists out all the PDF's that are located inside. I then took it a step further and started searching Google books and bringing back the picture and description of these books. For some of the books this works perfectly, but for a good number of them I get this error...
Warning: reset() expects parameter 1 to be array, null given in bookDescriber.php on line 49
This the code that is giving this error (this is all inside a big foreach, which lists all the PDFs in the directory). the last line of this code is line 49.
//search GoogleBooks for a description
$item = file_get_contents("https://www.googleapis.com/books/v1/volumes?q=$v&maxResults=1");
$item = json_decode($item);
$item = reset($item->items);
the $v in the above url is simply the filename of the book, so this is one of the links it would generate and as you can see this does return information... (if you copy the entire link all the way to maxResults=1 then the data is returned, could it be that sometimes the spaces in the URL don't matter and sometimes they do?? I'm lost)
https://www.googleapis.com/books/v1/volumes?q=Ajax the definitive guide.pdf&maxResults=1
so why is the first parameter in my reset() set to null??? Help please!!

I've tested around with that snippet and it can be recreate if:
$v is blank
The book doesn't exist
If the book doesn't exist, the null error is thrown and Google returns:
{
"kind": "books#volumes",
"totalItems": 0
}
This isn't enough information to create an array. You are better off having a check like so:
<?php
$item = file_get_contents("https://www.googleapis.com/books/v1/volumes?q=$v&maxResults=1");
if(is_array($item))
{
$item = json_decode($item);
$item = reset($item->items);
}
else
{
return false; // echo 'no book';
}
?>

Related

Filter a php array to only elements that have a matching value to $name in $data

I have a php script getting all folders in a posts folder and making them into a list.
I have a $postinfo_str variable assigned to a json file for each folder which I am using to store post date and category/tag info etc in.
I also have a $pagetitle variable assigned to a title.php include file for each folder. So say I am on a "June 2018" archive page, the text in that file will be "June 2018". If I am on say a "Tutorials" category page, that will be the text in the title.php.
In the json file, I have:
{
"Arraysortdate": "YYYYMMDD",
"Month": "Month YYYY",
"Category": ["cat1", "cat2", "etc"]
}
I am ordering the array newest to oldest using krsort with Arraysortdate as key.
How do I filter the array using $pagetitle as input, finding if there is a match in $postinfo_str, and if there isn't, remove that folder from the array?
All I can seem to find regarding array sorting is where the info in the $pageinfo_str is basically the array and so by that, the $title is the input and the output is the matching text from the $postinfo_str, whereas I want the output to be the folders that only have the matching text in the $postinfo_str to what the input ($pagetitle) is.
Here is my code I have.. Keep in mind this is flat file, I do not want a database to achieve this. See comments if you want an explaination.
<?php
$BASE_PATH = '/path/to/public_html';
// initial array containing the dirs
$dirs = glob($BASE_PATH.'/testblog/*/posts/*', GLOB_ONLYDIR);
// new array with date as key
$dirinfo_arr = [];
foreach ($dirs as $cdir) {
// get current page title from file
$pagetitle = file_get_contents("includes/title.php");
// get date & post info from file
$dirinfo_str = file_get_contents("$cdir/includes/post-info.json");
$dirinfo = json_decode($dirinfo_str, TRUE);
// add current directory to the info array
$dirinfo['dir'] = $cdir;
// add current dir to new array where date is the key
$dirinfo_arr[$dirinfo['Arraysortdate']] = $dirinfo;
}
// now we sort the new array
krsort($dirinfo_arr);
foreach($dirinfo_arr as $key=>$dir) {
$dirpath = $dir['dir'];
$dirpath = str_replace('/path/to/public_html/', '', $dirpath);
?>
<!--HTML HERE SUCH AS--!>
TEXT <br>
<?php
};
?>
I have difficulties following your problem description. Your code example is slightly confusing. It appears to load the same global includes/title.php for each directory. Meaning, the value of $pagetitle should be the same every iteration. If this is intended, you should probably move that line right outside the loop. If the file contains actual php code, you should probably use
$pagetitle = include 'includes/title.php';
or something similar. If it doesn't, you should probably name it title.txt. If it is not one global file, you should probably add the path to the file_get_contents/include as well. (However, why wouldn't you just add the title in the json struct?)
I'm under the assumption that this happened by accident when trying to provide a minimal code example (?) ... In any case, my answer won't be the perfect answer, but it hopefully can be adapted once understood ;o)
If you only want elements in your array, that fulfill certain properties, you have essentially two choices:
don't put those element in (mostly your code)
foreach ($dirs as $cdir) {
// get current page title from file
$pagetitle = file_get_contents("includes/title.php");
// get date & post info from file
$dirinfo_str = file_get_contents("$cdir/includes/post-info.json");
$dirinfo = json_decode($dirinfo_str, TRUE);
// add current directory to the info array
$dirinfo['dir'] = $cdir;
// add current dir to new array where date is the key
// ------------ NEW --------------
$filtercat = 'cat1';
if(!in_array($filtercat, $dirinfo['Category'])) {
continue;
}
// -------------------------------
$dirinfo_arr[$dirinfo['Arraysortdate']] = $dirinfo;
array_filter the array afterwards, by providing a anonymous function
// ----- before cycling through $dirinfo_arr for output
$filtercat = 'cat1';
$filterfunc = function($dirinfo) use ($filtercat) {
return in_array($filtercat, $dirinfo['Category']));
}
$dirinfo_arr = array_filter($dirinfo_arr, $filterfunc);
you should read up about anonymous functions and how you provide local vars to them, to ease the pain. maybe your use case is bettersuited for array_reduce, which is similar, except you can determine the output of your "filter".
$new = array_filter($array, $func), is just a fancy way of writing:
$new = [];
foreach($array as $key => $value) {
if($func($value)) {
$new[$key] = $value;
}
}
update 1
in my code samples, you could replace in_array($filtercat, $dirinfo['Category']) with in_array($pagetitle, $dirinfo) - if you want to match on anything that's in the json-struct (base level) - or with ($pagetitle == $dirinfo['Month']) if you just want to match the month.
update 2
I understand, that you're probably just starting with php or even programming, so the concept of some "huge database" may be frightening. But tbh, the filesystem is - from a certain point of view - a database as well. However, it usually is quite slow in comparison, it also doesn't provide many features.
In the long run, I would strongly suggest using a database. If you don't like the idea of putting your data in "some database server", use sqlite. However, there is a learning curve involved, if you never had to deal with databases before. In the long run it will be time worth spending, because it simplifys so many things.

PHP Nested Starcraft 2 Ladder Api

I want to make a personal profile page for my Starcraft 2 Clan with the API in PHP.
The normal stats are working for me.
$json = file_get_contents('http://eu.battle.net/api/sc2/profile/3077083/1/gbot/');
$obj = json_decode($json);
echo $obj->displayName;
However when I'll want to use the ladder stats I can't even display one variable.
$json = file_get_contents('
http://eu.battle.net/api/sc2/profile/3077083/1/gbot/ladders?locale=en_GB');
$lad = json_decode($json);
So how can I display the stats from the child with HOTS_SOLO in it?
This is just basic array access?
$json = file_get_contents('http://eu.battle.net/api/sc2/profile/3077083/1/gbot/ladders?locale=en_GB');
$data= json_decode($json);
$currentSeason = $data->currentSeason;
foreach ($currentSeason as $obj) {
foreach ($obj->ladder as $ladder) {
if ($ladder->matchMakingQueue == 'HOTS_SOLO') {
// this is the ladder we want to display
echo $ladder->ladderName; // Tychus Theta
}
}
}
There appears to be a newline in your URL (it starts on one line, where the whole literal begins on the line before). The file_get_contents() may be failing.
If that's not the problem, then it's something more subtle. Firefox/Chrome don't seem to have a problem with it. If json_decode is choking, it might be a forgiveable syntax issue. Try saving the data locally, and then removing components until it parses, and see if you can then do a string-replace or something to fix it, going forward.

Using text from a file to point to another file to read

Note: I'm sorry if the title was a little unclear couldn't think of another way to put it.
I am making a PHP posting system for a blog like website. I have a file called posts.txt which has information that points to other text files. These other text files have the physical post content in them. I know this is not the best way to do it but for now this is what I'm doing.
A sample of the posts.txt:
posts/topDownShooter.txt
posts/leapMotionSandbox.txt
end
The first two lines point to other text files that contain post content. The last line "end" lets the program know that all the post "pointers" are done
Here is a sample of a post like topDownShooter.txt
programming
Top Down Shooter
The actual post content goes here
end
The first line is a tag for organization. The second line is the title of the post. And the third is the actual content. The last line serves the same purpose.
Here is my PHP code:
I use "<--" for comments
<?php
$posts = "posts/posts.txt"; <--Pointer to the location of the posts.txt
$postsLines = file($posts);
$fetchingPost = TRUE; <--For while loop
$postNumber = 0;
$postPointer; <--In the example of posts.txt this would be the second or third line
$postTag;
$postTitle;
$postContent;
$endCondition = "end";
while ($fetchingPost == TRUE) {
$endOfFile = strcmp($postsLines[$postNumber], $endCondition);
if ($endOfFile == 0) {
$fetchingPost = FALSE;
}
if ($endOfFile <> 0) {
$postPointer[$postNumber] = $postsLines[$postNumber];
$postTag[$postNumber] = file($postPointer[$postNumber]); <--The problem, see below
$postNumber = $postNumber + 1;
}
}
?>
The Problem: It will not let me use a line that I take out of posts.txt as a "pointer" for accessing topDownShooter.txt or anything like that. I thought that the value I was pulling out of posts.txt was a string but it is not. Is there anyway that I can convert this to a string or make it work?
EDIT:
in short:
is there anyway to take something from $postsLines = file("somerandomtxtfile.txt); and make %postsLines[0] a string?
I'm not sure if I understand your question, but I'd try replacing the line by this
$postTag[$postNumber] = file_get_contents($postPointer[$postNumber]);
Answering the question in your edit, you can do that like this:
$postLines = explode(PHP_EOL, file_get_contents("somerandomtxtfile.txt"));

PHP arrays within arrays in session

I've been using PHP for a little bit, but only doing basic tasks, and have gotten stuck while trying to build part of a knowledgebase.
While creating an article, you can upload screenshots - these need to be stored in a staging area until the article is saved, and I've got their information saved into the users session.
In POST upload:
...
$new_ss = array();
$new_ss['display_name'] = $ss_name;
$new_ss['server_path'] = "../uploads/"; /* outside of doc root */
$new_ss['server_path'] .= hash_file('md5', $ss_tmp_name) . "_" . $ss_name;
if ( #move_uploaded_file($ss_tmp_name, $new_ss['server_path']) )
{
$_SESSION['article']['screenshots'] .= $new_ss;
...
Then trying to display the upload to the user within the editing page:
if ( is_array($_SESSION['article']['screenshots']) && count($_SESSION['article']['screenshots']) > 0 )
{
echo "<table border=\"1\">\n";
foreach ( $_SESSION['article']['screenshots'] as $ss )
{
... display table of uploaded images ...
The trouble is, PHP isn't seeing $_SESSION['article']['screenshots'] as an array - and I can't see why.
After following the answer here:
PHP foreach() with arrays within arrays? I tried quickly doing the following:
function print_array($key, $item) {
echo "$key -> $item\n";
}
...
{
$_SESSION['article']['screenshots'] .= $new_ss;
array_walk_recurisve($_SESSION['article']['screenshots'], 'print_array');
...
however I get the error "expects parameter 1 to be array, string given".
If I do an 'error_log($_SESSION['article']['screenshots']);' it just prints "Array" for however many images are uploaded, and print_r just printed '1' by itself.
Can someone shed some light please?
Well I'm not really sure which of your key should be an array, in this line:
$_SESSION['article']['screenshots'] .= $new_ss;
You're making it a string by concatenating it. If you want to append as an array, you should probably do this:
$_SESSION['article']['screenshots'][] = $new_ss;

Problems using the Amazon API to search ISBN

I'm having a few issues using the amazon API to search for ISBN.
The code seams to work for a FEW isbn's and returns some results however the majority of books (mainly factual/reference books) I search for via ISBN return no results.
To test I am getting the ISBN-10 number from amazon. I have also then tested by searching for this isbn through their own search.
This is the code we use to get the results.. I dont suppose anyone can spot a flaw?
function getBooks($isbn){
$client = new AmazonECS('AWS_API_KEY', 'AWS_API_SEECRET_KEY', 'co.uk', 'tutorp-21');
$response = $client->responseGroup('Small,Images,EditorialReview')->category('Books')->search($isbn);
$books = array();
if($response->Items->TotalResults > 1){
foreach($response->Items->Item as $item)
$books[] = parseItem($item);
}else if($response->Items->TotalResults == 1){
$books[] = parseItem($response->Items->Item);
}
return $books;
}
Cheers
Edit : Just to clarify... The problem we are facing is that only some ISBN numbers return results. Even though these books exist in Amazon they dont seam to return any results when searched through the API
Without looking into the AmazonECS API, I'd expect TotalResults of 1 to return an array containing a single item still; the assignment in your else clause via parseItem($response->Items->Item) will fail accordingly (i.e. books[] remains empty), because $response->Items->Item is still an array and cannot be parsed into an item.
Consequently you should drop the else clause and adjust your condition to test for 0 instead (or >= 1 of course), e.g.:
// [...]
if($response->Items->TotalResults > 0){
foreach($response->Items->Item as $item)
$books[] = parseItem($item);
}
// [...]
Update
The Show first 10 results example of the Amazon ECS PHP Library confirms my expectations, the result loop is implemented like so:
//check that there are items in the response
if (isset($response['Items']['Item']) ) {
//loop through each item
foreach ($response['Items']['Item'] as $result) {
// [...]
}
}
The problems was books that didn't have editorials. The code written works fine but needed exceptions for books being returned without all the information.

Categories