2
\$\begingroup\$

In PHP, I'm getting multiple series and dumping various bits of information into an array. I will be left with 180 items (if I put in 30 series details that have 6 events per series)

$eventsArray = explode(',', $events); // This gets passed in via a param
\load_curl();
$array = Array();
$curl_array = array();

$ch = curl_multi_init();
foreach($eventsArray as $count => $id) {
    $curl_array[$count] = curl_init("https://www.eventbriteapi.com/v3/series/".$id."/events/?expand=ticket_classes&token=XXX");
    curl_setopt($curl_array[$count], CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($curl_array[$count], CURLOPT_VERBOSE, true);
    curl_setopt($curl_array[$count], CURLOPT_SSL_VERIFYPEER, false);
    curl_multi_add_handle($ch, $curl_array[$count]);
}

do {
    curl_multi_exec($ch, $exec);
} while($exec > 0);

foreach($eventsArray as $count => $id) {
    $returned = curl_multi_getcontent($curl_array[$count]);
    $json = \json_decode($returned,true);
    foreach ( $json["events"] as $event) {
        $remaining = $event["ticket_classes"][0]["quantity_total"] - $event["ticket_classes"][0]["quantity_sold"];
        $array[] = Array('id'=>$event["id"],
                         'url'=>$event["url"],
                         'status'=>$event["status"],
                         'remaining'=>$remaining,
                         'start'=>date('l, jS F Y', strtotime($event["start"]["local"]))
                   );
    }
}

foreach($eventsArray as $count => $id) {
    curl_multi_remove_handle($ch, $curl_array[$count]);
}

curl_multi_close($ch); 

foreach($eventsArray as $count => $id) {
    curl_close($curl_array[$count]);
}

$array = array_chunk($array, 30);
$array = json_encode($array);
return $array;

I then use EJS to display the information like below. The first item in each chunk is displayed in a row, then second item of each chunk in the next row etc.

<% for(var i=0; i<30; i++) { %>
    <tr>
        <th><%= this[0][i]['start'] %></th>
    <% for (var x=0; x<6; x++) { 

    if (this[x][i]['status'] == 'live') {
        if (this[x][i]['remaining']<=0) {
            status='<span class="badge">FULL</span>'; 
            style = 'class="danger"';
        }
        else {
            status ='<a href="'+ this[x][i]['url'] +'">Book now</a><br><span class="badge badge-success">'+this[x][i]['remaining']+' AVAILABLE</span>'; 
            style = 'class="success"';
        }
    }
    else {
            status='<span class="badge">COMPLETE</span>'; 
            style = 'class="warning"';
    }

    %>
        <td <%=style%>> <%=status%></td>
    <% } %>
    </tr>
<% } %>

It works but takes about 5 seconds to run. What could I do to make it faster? Is there much improvement that could be made?

\$\endgroup\$

2 Answers 2

2
\$\begingroup\$

Use a local database to store information

You could start by testing what takes the longest, and concentrate your efforts there. I cannot do this test. However, getting multiple bits of information, from an external API, can never be quick. This is probably what is slowing you down.

The API is: https://www.eventbrite.com/developer/v3

I had a very short look at the API you're using, and quickly stopped when I noticed it was quite complex. :-)

Do you retrieve information from the API for every page you render? Does this mean that the same information is requested from the API several times?

In that case it would be better to store the retrieved information in a local database, and use the information from your local database to build the web pages.

The API has webhooks. These can be useful to update the information in your database. Use them.

I know this isn't really an answer that reviews your code.

\$\endgroup\$
3
  • \$\begingroup\$ At the moment, it's only once per page but future use could see it being multiple times per page. The database storage is an option but we're using a very stripped down version of MySQL that doesn't allow updates \$\endgroup\$
    – pee2pee
    Oct 3, 2017 at 8:57
  • \$\begingroup\$ Even if it is only once per page, if that page is requested multiple times, it will be more efficient to use a local storage for the information. There are alternatives to a MySQL database. You could, for instance, use SQLite3 and store the information in a single file. \$\endgroup\$ Oct 3, 2017 at 9:01
  • \$\begingroup\$ Sorry - forgot to say it's a locked down 3rd party system so realistically, our only option to not utilise a DB \$\endgroup\$
    – pee2pee
    Oct 3, 2017 at 9:19
1
\$\begingroup\$

A few suggestions...

  • Try to reduce the number of loops you call and combine them where possible.
  • Is cutting out the EJS altogether an option?
  • Use the variable name $count to mean a "total". If you are dealing with a "counter" or "index" or "integer", I recommend $i or if that is already in use, $x (or $j is a common secondary counter name).
  • I assume foreach($eventsArray as $count=>$id){curl_close($curl_array[$count]);} is unnecessary because the php manual doesn't use this with curl_multi.
  • Rather than generate an array, chunk it, json encode it, display it with another set of nested loops in EJS, perhaps returning a concatenated string will speed things up due to less array handling.

I didn't test my code (and I have no prior experience with curl_multi) but this is theoretically what I had in mind to return the "guts" of the table from the function:

function curlToTable($events){
    $eventsArray=explode(',',$events);
    $curl_array=array();
    $html='';

    load_curl();
    $ch=curl_multi_init();
    foreach($eventsArray as $i=>$id){
        $curl_array[$i] = curl_init("https://www.eventbriteapi.com/v3/series/".$id."/events/?expand=ticket_classes&token=XXX");
        curl_setopt($curl_array[$i], CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($curl_array[$i], CURLOPT_VERBOSE, true);
        curl_setopt($curl_array[$i], CURLOPT_SSL_VERIFYPEER, false);
        curl_multi_add_handle($ch, $curl_array[$i]);
    }

    do{
        curl_multi_exec($ch, $exec);
    }while($exec > 0);

    $x=0;
    foreach($eventsArray as $i=>$id) {
        $returned=curl_multi_getcontent($curl_array[$i]);
        $json=json_decode($returned,true);
        foreach($json["events"] as $event){
            if($x%6==0){
                if($x!=0){
                    $html.="</tr>";
                }
                $html.="<tr>";
                    $html.="<th>".date('l, jS F Y',strtotime($event["start"]["local"]));
                $html.="</tr>";
            }
            if($event["status"]=='live'){
                if(($remaining=$event["ticket_classes"][0]["quantity_total"] - $event["ticket_classes"][0]["quantity_sold"])<=0){
                    $html.="<td class=\"danger\"> <span class=\"badge\">FULL</span></td>";
                }else{
                    $html.="<td class=\"success\"> <a href=\"{$event["url"]}\">Book now</a><br><span class=\"badge badge-success\">$remaining AVAILABLE</span>";
                }
            }else{
                $html.="<td class=\"warning\"> <span class=\"badge\">COMPLETE</span>";
            }
            ++$x;
        }
        $html.="</tr>";
        curl_multi_remove_handle($ch, $curl_array[$i]);
    }
    curl_multi_close($ch);
    return $html;
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.