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.
Related
I am using Simple_html_dom trying to grab Reputation points and make a check on those values and then extract only those user profiles whose Repu is greater that 200. Below is the code, It works fine when doing this
`
$html2=str_get_html($html1);
foreach ($html2->find('.user-details') as $value) {
foreach($html2->find('.reputation-score') as $repu){
echo (int)$repu->plaintext.$value.'<br>';
}
}
When doing the above i am getting all thereputation and the user detailswell each line, looks fine till now. But now i wanna perform aconditional checkand then echo only those profiles whose repo is higher than100`. So when i am trying the below code
`
$html2=str_get_html($html1);
foreach ($html2->find('.user-details') as $value) {
foreach($html2->find('.reputation-score') as $repu){
if($repu>100)
{
echo ($repu->plaintext.$value.'<br>';
}
}
}
I am getting an error saying Object of class simple_html_dom_node could not be converted to int seeing that i've tried doing (int) to convert and then echo still couldnt solve
Any help here ?
So crazy! I have a bug that's 100% reproducible, it happens in only a few lines of code, yet I cannot for the life of me determine what the problem is.
My project is a workout maker, and the mystery involves two functions:
get_pairings: It makes a set of $together_pairs (easy) and $mixed_pairs (annoying), and combines them into $all_pairs, used to make the workout.
make_mixed_pairs: this has different logic depending on whether it's a partner vs solo workout. Both cases return a set of $mixed_pairs (in the same exact format), called by the function above.
The symptoms/clues:
The case of the solo workout is fine, $all_pairs will only contain $mixed_pairs (because as it's defined, $together_pairs are only for partner workouts)
In the case of the a partner workout, when I combine the two sets in get_pairings(), $all_pairs only successfully gets the first set I give it! (If I swap those lines at step 2 and add $together_pairs first, $all_pairs contains only those. If I do $mixed_pairs first, $all_pairs contains only that).
Then if I uncomment that second-to-last line in make_mixed_pairs() just for troubleshooting to see what happens, then $all_pairs does successfully include exercises from both sets!
That suggests the problem is something I'm doing wrong in making the arrays in make_mixed_pairs(), but I confirmed that the resulting format is identical in both cases.
Anyone see what else I could be missing? I've been narrowing down this bug for 4 hours so far- I can't make it any smaller, and I can't see what's wrong :(
Update: I updated the for loop in make_mixed_pairs() to stop at $mixed_pair_count - 1 (instead of just $mixed_pair_count), and now I sometimes get one single 'together_pair' mixed in the $all_pairs results; the same damn one each time, weirdly. Though it's not 'fixed', because again when I change the order that I add the two sets in get_pairings, when I add $together_pairs first, then $all_pairs is ENTIRELY those- it's so strange...
Here are the functions: first get_pairings (relevant part is right before and after step 2):
/**
* Used in make_workout.php: take the user's available resources, and return valid exercises
*/
function get_pairings($exercises, $count, $outdoor_partner_workout)
{
// 1. Prep our variables, and put exercises into the appropriate buckets
$mixed_exercises = array();
$together_pairs = array();
$mixed_pairs = array();
$all_pairs = array();
$selected_pairs = array();
// Sort the valid exercises: self_pairing exercises go as they are, with extra
// array for consistent formatting. Mixed ones go into $mixed_exercises array
// for more specialized pairing in make_mixed_pairs
foreach($exercises as $exercise)
{
if ($exercise['self_pairing'])
{
$pair = array($exercise);
array_push($together_pairs, [$pair]);
}
else
{
$this_exercise = array($exercise);
array_push($mixed_exercises, $this_exercise);
}
}
// Now get the mixed_pairs
$mixed_pairs = make_mixed_pairs($mixed_exercises, $outdoor_partner_workout);
// 2. combine together into one set, and select random pairs for the workout
// Add both sets to the array of all pairs (to pick from afterward)
$all_pairs += $mixed_pairs;
$all_pairs += $together_pairs;
// Now let's choose at random our desired # of pairs, and save them in $selected_pairs
$pairing_keys = array_rand($all_pairs, $count);
foreach($pairing_keys as $key)
{
array_push($selected_pairs, $all_pairs[$key]);
}
// Finally, shuffle it so we don't always see the self-pairs first
shuffle($selected_pairs);
return $selected_pairs;
}
And the other one- make_mixed_pairs: there are two cases, the first is complicated (and shows the bug) and the second is simple (and works):
/**
* Used by get_pairings: in case of a partner workout that has open space (where
* one person can travel to a point while the other does an exercise til they return)
* we'll pair exercises in a special way. (If not, fine to grab random pairs)
*/
function make_mixed_pairs($mixed_exercises, $outdoor_partner_workout)
{
$mixed_pairs = array();
// When it's an outdoor partner workout, we want to pair travelling with stationary
// put them into arrays and then we'll make pairs using one from each
if ($outdoor_partner_workout)
{
$mixed_travelling = array();
$mixed_stationary = array();
foreach($mixed_exercises as $exercise)
{
if ($exercise[0]['travelling'])
{
array_push($mixed_travelling, $exercise);
}
else
{
array_push($mixed_stationary, $exercise);
}
}
shuffle($mixed_travelling);
shuffle($mixed_stationary);
// determine the smaller set, and pair exercises that many times
$mixed_pair_count = min(count($mixed_travelling), count($mixed_stationary));
for ($i=0; $i < $mixed_pair_count; $i++)
{
$this_pair = array($mixed_travelling[$i], $mixed_stationary[$i]);
array_push($mixed_pairs, $this_pair); // problem is adding them here- we get only self_pairs
}
}
// Otherwise we can just grab pairs from mixed_exercises
else
{
// shuffle the array so it's in random order, then chunk it into pairs
shuffle($mixed_exercises);
$mixed_pairs = array_chunk($mixed_exercises, 2);
}
// $mixed_pairs = array_chunk($mixed_exercises, 2); // when I replace it with this, it works
return $mixed_pairs;
}
Oh for Pete's sake: I mentioned this to a friend, who told me that union is flukey in php, and that I should use array_merge instead.
I replaced these lines:
$all_pairs += $together_pairs;
$all_pairs += $mixed_pairs;
with this:
$all_pairs = array_merge($together_pairs, $mixed_pairs);
And now it all works
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';
}
?>
I am using PHP to get the contents of an API. The problem is, sometimes that API just sends back a 502 Bad Gateway error and the PHP code can’t parse the JSON and set the variables correctly. Is there some way I can keep trying until it works?
This is not an easy question because PHP is a synchronous language by default.
You could do this:
$a = false;
$i = 0;
while($a == false && $i < 10)
{
$a = file_get_contents($path);
$i++;
usleep(10);
}
$result = json_decode($a);
Adding usleep(10) allows your server not to get on his knees each time the API will be unavailable. And your function will give up after 10 attempts, which prevents it to freeze completely in case of long unavailability.
Since you didn't provide any code it's kind of hard to help you. But here is one way to do it.
$data = null;
while(!$data) {
$json = file_get_contents($url);
$data = json_decode($json); // Will return false if not valid JSON
}
// While loop won't stop until JSON was valid and $data contains an object
var_dump($data);
I suggest you throw some sort of increment variable in there to stop attempting after X scripts.
Based on your comment, here is what I would do:
You have a PHP script that makes the API call and, if successful, records the price and when that price was acquired
You put that script in a cronjob/scheduled task that runs every 10 minutes.
Your PHP view pulls the most recent price from the database and uses that for whatever display/calculations it needs. If pertinent, also show the date/time that price was captured
The other answers suggest doing a loop. A combo approach probably works best here: in your script, put in a few loops just in case the interface is down for a short blip. If it's not up after say a minute, use the old value until your next try.
A loop can solve this problem, but so can a recursive function like this one:
function file_get_contents_retry($url, $attemptsRemaining=3) {
$content = file_get_contents($url);
$attemptsRemaining--;
if( empty($content) && $attemptsRemaining > 0 ) {
return file_get_contents_retry($url, $attemptsRemaining);
}
return $content;
}
// Usage:
$retryAttempts = 6; // Default is 3.
echo file_get_contents_retry("http://google.com", $retryAttempts);
I am just starting with Sphinx. So far I got it installed successfully, got a table called profiles on my MySQL database indexed and am able to get the correct results back using the PHP API. I am using CodeIgniter so I wrapped the default PHP API as a CodeIgniter library.
Anyway this is how my code looks like:
$query = $_GET['q'];
$this->load->library('sphinxclient');
$this->sphinxclient->setMatchMode(SPH_MATCH_ANY);
$result = $this->sphinxclient->query($query);
$to_fetch = array();
foreach($result['matches'] as $key => $match) {
array_push($to_fetch, $key);
}
The array $to_fetch contains the ids of the matched table rows. Now I can use a typical MySQL query to get all the relevant users to display on the search page like so:
$query = 'SELECT * FROM profiles WHERE id IN('. join(',', $to_fetch) . ')';
My question are:
is this the right way to go about it? or is there a default "Sphinx way of doing it" that would be better for performance .
secondly, all I get back at the moment is the id of the matched table rows. I also want the part of the text in the column that matched. For example if a someone searches for the keyword dog and a user on the profiles table had in their about column the following text:
I like dogs. I also like ice cream.
I would like Sphinx to return:
I like <strong>dogs</strong>. I also like ice cream.
How can I do that? I tried to play around with the buildExcerpts() function but can't get it to work.
EDIT
This is how I am getting excerpts now:
// get matched user ids
$to_fetch = array();
foreach($result['matches'] as $key => $match) {
array_push($to_fetch, $key);
}
// get user details of matched ids
$members = $this->search_m->get_users_by_id($to_fetch);
// build excerpts
$excerpts = array();
foreach($members as $member) {
$fields = array(
$member['about'],
$member['likes'],
$member['dislikes'],
$member['occupation']
);
$options = array(
'before_match' => '<strong class="match">',
'after_match' => '</strong>',
'chunk_separator' => ' ... ',
'limit' => 60,
'around' => 3,
);
$excerpt_result = $this->sphinxclient->BuildExcerpts($fields, 'profiles', $query, $options);
$excerpts[$member['user_id']] = $excerpt_result;
}
$excerpts_to_return = array();
foreach($excerpts as $key => $excerpt) {
foreach($excerpt as $v) {
if(strpos($v, '<strong class="match">') !== false) {
$excerpts_to_return[$key] = $v;
}
}
}
As you can see I am searching each query across 4 different mysql columns:
about
likes
dislikes
occupation
Because of this I don't know which of the 4 columns contains the matched keyword. It could be any of them or even more than one. So I have no choice but to run the contents of all 4 columns through the BuildExcerpts() function.
Even then I don't know which one the BuildExcerpts() returned with the <strong class="match"> tags. So I run a stpos check on all values returned by BuildExcerpts() to finally get the proper excerpt and map it to the user whose profile it belongs to.
Do you see a better way than this given my situation where I need to match against the contents of 4 different columns?
Yes that looks good way. One thing to remember the rows coming back from Mysql probably won't be in the order from sphinx.
See the FAQ on sphinx site for how to use FIELD() but personally I like to put the rows from sphinx into associative array, then just loop though the sphinx I'd list and get the row from the array. Avoids a sorting phase altogether at the expense of memory!
As for highlighting, yes do persevere with buildExcerpts - that's is the way to do it.
edit to add, this demo
http://nearby.org.uk/sphinx/search-example5-withcomments.phps
demonstrates both getting rows from mysql and "sorting" in the app. And buildExcerpts.