Sort query results by HTML table column - php

I'm looking for a more efficient, elegant and secure way to sort data displayed inside an HTML table. This is what I've come up with so far and it looks somewhat bloated / noobish.
I also thought of something like storing the sorting in a $_SESSION so I don't have to carry the currently selected order over to the next page "manually" within the URL. Maybe a "safe&simple" piece of JavaScript+PHP (but no frameworks please) would make sense? My thoughts go in circles for hours now.
<?php
$ro_arr = array(
"kid" => "kid",
"kwd" => "Keyword",
"cpc" => "ApproximateCPC",
"cmp" => "Competition",
"mov" => "MonthlyValue",
"gms" => "GlobalMonthlySearches",
"lms" => "LocalMonthlySearches",
"dfc" => "KeywordDifficulty",
"com" => "com",
"net" => "net",
"org" => "org",
);
if (!empty($_GET['ro']) && strlen($_GET['ro']) == 7 && array_key_exists($col = substr($_GET['ro'], 0, 3), $ro_arr)) {
$dir = (substr($_GET['ro'], 4, 3) == 'asc' ? "ASC" : "DESC");
$res_order = $res_arr[''. $col .''] ." ". $dir;
} else {
$_GET['ro'] = "kid_asc";
$res_order = "kid ASC";
}
?>
<!-- just for testing -->
<pre><?php echo $res_order; ?></pre>
<!-- done testing -->
<table>
<tr>
<td>Keyword</td>
<td>Comp.</td>
<td>Ad CPC</td>
<td>Value</td>
<td>Global Searches</td>
<td>Local Searches</td>
<td>Difficulty</td>
<td width="22">com</td>
<td width="22">net</td>
<td width="22">org</td>
</tr>
</table>

You can reduce the amount of code to almost a half if you'll use two parameters instead of one:
The parameter by which you're sorting: kid, com, net, org...
Order: asc, dsc

If your table isn't too large and you're not adverse to using jQuery, use tablsorter. Once you get into the thousands of rows, client side sorting can get a little unwiledy.

Related

Trying to display full continent name based on 2 letter code

I need to display site visitor's continent. I am using geoip functionality to pull 2 letter code, which I can get to work very easily. However, just displaying 'AS' for Asia to the site visitor is clearly undesirable. So I'm trying to convert that. This is what I am trying to do. . .
<?php
$continent = geoip_continent_code_by_name($_SERVER['REMOTE_ADDR']);
$africa = array('AF');
$antarctica = array('AN');
$asia = array('AS');
$europe = array('EU');
$northamerica = array('NA');
$oceania = array('OC');
$southamerica = array('SA');
if ($africa) {
echo 'Africa';
}
elseif ($antarctica) {
echo 'Antarctica';
}
elseif ($asia) {
echo 'Asia';
}
elseif ($europe) {
echo 'Europe';
}
elseif ($northamerica) {
echo 'North America';
}
elseif ($oceania) {
echo 'Australia and Oceania';
}
elseif ($southamerica) {
echo 'South America';
}
else {
echo '';
}
?>
It just displays 'Africa' no matter where the site visitor, so it's getting stuck there. I'm reading though PHP tutorials but can't figure out what I'm doing wrong. My if, else and elsifs look good as far as I can tell.
Well, you're kind of going about it wrong.
You're getting the code correctly with your first line, but then you are creating a bunch of different arrays, each containing one of the possible codes. Then you are checking for the existence of each array, and since you just created them, they do exist, so your IF block will stop with the first check and output Africa.
What you want to do is create one array that contains all the codes as keys, with the output name as values, and then just use the code you got from $_SERVER to return the matching value from that array. (I got the list of codes from the manual)
$continent = geoip_continent_code_by_name($_SERVER['REMOTE_ADDR']);
$continents = [
'AF' => 'Africa',
'AN' => 'Antarctica',
'AS' => 'Asia',
'EU' => 'Europe',
'NA' => 'North America',
'OC' => 'Oceania',
'SA' => 'South America',
];
echo $continents[$continent];
It's worth a little explanation for WHY your IF block functions the way it does. PHP is loosely typed, meaning that you don't have to explicitly set the type of variables. So when PHP encounters a variable it has to guess about how to use it. So when you say if($africa), php tries to make sense of $africa in the context of a boolean question, and since it DOES exist and is not 0 or false, it sees it as TRUE and executes the first block.

Is this a reasonably secure way to use $_GET

I am just a weekend coder and only work on my own projects but I would like to use $_GET in a reasonably secure way. I typically use $_GET from a table with many items that I would like to perform some action on (Edit, Delete). Do any of you veterans see any security issues with the functions I have created or a simpler more elegant way of doing it? I appreciate any input, Thanks.
<?php session_start();
if (empty($_SESSION['SecretKey'])) {
$_SESSION['SecretKey'] = bin2hex(openssl_random_pseudo_bytes(16));
}
function GetURLEncode($ArrayData,$SecretKey,$Echo = true) {
$GetQuery = http_build_query($ArrayData,'','&');
$Checksum = http_build_query(Array("Checksum" => hash_hmac('ripemd160', $GetQuery, $SecretKey)));
if ($Echo) {
echo ''.htmlspecialchars($ArrayData['Action']).'';
} else {
return "?".$GetQuery."&".$Checksum;
}
}
function GetURLDecode($GetData,$SecretKey,&$ReturnData) {
$Checksum = $GetData['Checksum'];
unset($GetData['Checksum']);
$GetQuery = http_build_query($GetData,'','&');
if (hash_equals(hash_hmac('ripemd160', $GetQuery, $SecretKey),$Checksum)) {
$ReturnData = $GetData;
return true;
}
$ReturnData = "";
return false;
}
if (!empty($_GET)) {
if (GetURLDecode($_GET,$_SESSION['SecretKey'],$ReturnData)) {
echo "Array Returned<br>";
echo var_dump($ReturnData)."<br><Br>";
} else {
echo "Checksum Error<br><br>";
}
}
//Example 1
$MyArray1 = Array ("FirstName" => "John",
"LastName" => "Doe",
"Adderss" => "12345 MyStreet",
"City" => "Apple Valley",
"State" => "California");
echo "Sample 1<br>";
$URL = GetURLEncode($MyArray1,$_SESSION['SecretKey'],false);
echo 'Click Me';
//Example 2
$MyArray2 = Array(Array("Id" => 0,"Make" => "Chevy","Model" => "HHR"),
Array("Id" => 1,"Make" => "Chevy","Model" => "Corvette"),
Array("Id" => 2,"Make" => "Ford","Model" => "Mustang"),
Array("Id" => 3,"Make" => "Nissan","Model" => "Sentra"),
Array("Id" => 4,"Make" => "Ford","Model" => "Ranger"),
Array("Id" => 5,"Make" => "Dodge","Model" => "Charger"));?>
<br><br>
<table>
<th>sample 2</th>
<?php foreach ($MyArray2 as $Array) { ?>
<tr>
<td><?= $Array['Make'];?></td>
<td><?= $Array['Model'];?></td>
<td><?php GetURLEncode(array("Id"=>$Array['Id'],"Action"=>"Edit"),$_SESSION['SecretKey']);?></td>
<td><?php GetURLEncode(array("Id"=>$Array['Id'],"Action"=>"Delete"),$_SESSION['SecretKey']);?></td>
</tr>
<?php } ?>
</table>
Hello there weekend coder, the only issue i see with using a GET method is that a user can directly change the GET data in the url. for example, lets take youtube for example ( at least back in the day ), each youtube video has a GET value of v and it's value is some random 64bit alphanumeric hex hash of digits and you can see it directly in the URL youtube com/watch?v=xxxxxxxxxxxx since this is so, you can manually change this value and it will take you to another video because you changed the video id number. this is useful because you can copy this link and send it to your friends.
on the other hand, POST is different as you cannot really directly change the POST data values being sent. though there some mischievous ways some may be able too, which is why form validation is always needed for POST forms and values!!!
if we changed youtube's methods to use POST, all youtube videos would have youtubeDOTcom as the URL and the video ID would be hidden underneath the page as POST. now the user cannot directly see their video's random unique ID and cannot send the link to others to be shared.
Hope this explains a bit, it depends on what type of information you are sending. if you think it should be secured and not visible to all users, use POST. if you want the link to be shared and changed often to view different pages,media, etc, that's not confidential, you can use GET

Random Content Array seems stuck

I have a random content script that has worked perfectly but now seems to have a glitch.
It's the "Spotlight On:" story on the upper lefthand corner at http://fiction.deslea.com/index2.php and the code is as follows:
$storyspotlights = array("bluevial", "biophilia", "real", "edgeofreality",
"limitsofperception", "markofcain", "spokenfor", "closer",
"feildelm", "purgatory", "elemental");
$randomstoryID = array_rand($storyspotlights);
$randomstory = $storyspotlights[$randomstoryID];
switch ($randomstory) {
case ($randomstory == 'closer'):
$storyspotlightheader = "<div class='storyspotlightheader'>Closer</div>";
$storyspotlighttext = "snip";
//some stories snipped
case ($randomstory == 'bluevial'):
$storyspotlightheader = "<div class='storyspotlightheader'>The Blue
Vial</div>";
$storyspotlighttext = "snip";
break;
//more stories snipped
}
print($storyspotlightheader);
print($storyspotlighttext);
My problem is - all the stories from Blue Vial to Spoken For appear when you refresh the page, in random order (although Blue Vial seems to stick a fair bit). These were the stories in the script originally.
Since then I have added the last four to the array and the content generation switch case fragment, but these last four stories never, ever appear in the randomiser. I've literally sat and refreshed for hours. I've confirmed over and over that the updated script is on the server, and even deleted and re-uploaded it.
I did try unset and also $storyspotlights = array() at the beginning of the script at various stages of troubleshooting, but to no avail. I also tried moving the new stories to the start of the array - no change there either.
What am I missing?
It's surprising this works at all. That's not how you use switch..case.
switch (<value to compare>) {
case <value to compare against>:
...
}
That means you write this:
switch ($randomstory) {
case 'closer':
...
}
With what you've written it's actually executing like:
if ($randomstory == ($randomstory == 'closer')) ...
Also make sure you have not actually forgotten some break statements, which would make the code fall through to the next case and indeed make certain cases "more sticky" than others.
Also, I'd simplify the whole thing to this:
$stories = array(
array('header' => '...', 'text' => '...'),
array('header' => '...', 'text' => '...'),
...
);
$story = $stories[array_rand($stories)];
echo $story['header'];
echo $story['text'];

Required output generated for json data

{"99.net":{"status":"regthroughothers","classkey":"dotnet"},
"99.org": {"status":"regthroughothers","classkey":"domorg"},
"99.mobi":{"status":"regthroughothers","classkey":"dotmobi"},
"99.name":{"status":"Invalid Domain Name","classkey":"dotname"},
"99.us":{"status":"regthroughothers","classkey":"domus"},
"99.com":{"status":"regthroughothers","classkey":"domcno"},
"99.info":{"status":"Invalid Domain Name","classkey":"dominfo"},
"99.co.uk":{"status":"available","classkey":"thirdleveldotuk"},
"99.biz":{"status":"Invalid Domain Name","classkey":"dombiz"},
"99.in":{"status":"Invalid Domain Name","classkey":"dotin"}}
I'm able to display the output with the following code:
$json1 = json_decode($response1);
foreach($json1 as $key=>$sel_rows)
{
echo $key ;
echo " status: ". $sel_rows->status." ";
echo " Class: ". $sel_rows->classkey." ";
echo "Price";
echo "<br>";
}<br>
Now, I need to sort it so that a table such as the following can be shown:
<table border="1">
<tr>
<td>.com</td>
<td>.net</td>
<td>.info</td>
<td>.org</td>
</tr>
<tr>
<td>ADD</td>
<td>ADD</td>
<td>ADD</td>
<td>ADD</td>
</tr>
</table>
I'm having trouble figuring out how to sort the response in a way that I can use to generate this table, using the response data to add tool tips to the ADD links (like dinakar.com).
$json1 = json_decode($response1, TRUE);
foreach($json1 as $key=>$sel_rows)
{
echo $key ;
echo " status: ". $sel_rows['status']." ";
echo " Class: ". $sel_rows['classkey']." ";
echo "Price";
echo "<br>";
}
It looks like you're not having a problem decoding the response, but rather normalizing it for what you need to display. To do that, you'll need to extract the TLD from the domain string, unless you know it ahead of time. Presumably you do, as it was used to request the response to begin with?
Anyway, the following code illustrates one way of getting it into an array suitable for you to pass to your view (or however you're doing it):
$response1 = <<< EOF
{"99.net":{"status":"regthroughothers","classkey":"dotnet"},
"99.org": {"status":"regthroughothers","classkey":"domorg"},
"99.mobi":{"status":"regthroughothers","classkey":"dotmobi"},
"99.name":{"status":"Invalid Domain Name","classkey":"dotname"},
"99.us":{"status":"regthroughothers","classkey":"domus"},
"99.com":{"status":"regthroughothers","classkey":"domcno"},
"99.info":{"status":"Invalid Domain Name","classkey":"dominfo"},
"99.co.uk":{"status":"available","classkey":"thirdleveldotuk"},
"99.biz":{"status":"Invalid Domain Name","classkey":"dombiz"},
"99.in":{"status":"Invalid Domain Name","classkey":"dotin"}}
EOF;
function get_tld($url) {
$host = parse_url($url);
$domain = $host['path'];
$tail = substr($domain, -7); // Watch out, gotcha! Be sure of this.
$tld = strstr($tail, ".");
return $tld;
}
$domains = array();
$json1 = json_decode($response1);
foreach ($json1 as $idx => $obj) {
$tld = get_tld($idx);
$domains[$tld] = array('tld' => $tld, 'status' => $obj->status, 'classkey' => $obj->classkey);
}
This is off the top of my head. The resulting $domains array looks like this (truncated for brevity):
Array
(
[.net] => Array
(
[tld] => .net
[status] => regthroughothers
[classkey] => dotnet
)
[.org] => Array
(
[tld] => .org
[status] => regthroughothers
[classkey] => domorg
)
Note, I'm not doing a whole lot of sanity here, but that should be enough to help you sink your teeth into it. You'd then just make your table head off the keys, and populate your add links with whatever information they need that was returned in the response.

Need to optimize this PHP script for "recent posts". Fatal error when post count is high

The code below is resulting in an error on a site in which there are ~ 1500 posts. It performs fine when post count is nominal, however, this heavy load is exposing the weakness of the code and I'd like to optimize it.
Interestingly, when I disable this menu and instead use the "Recent Posts" widget, the posts are drawn fine. So I'd probably do good to borrow from that code if I knew where to find it, or better yet, If I could call the widget directly in my theme, passing it a post count variable.
Fatal error: Allowed memory size of
33554432 bytes exhausted (tried to
allocate 16384 bytes) in
/home1/est/public_html/mysite/wp-includes/post.php
on line 3462
The code is below. Its purpose is to list "recent posts".
global $post;
$cat=get_cat_ID('myMenu');
$cathidePost=get_cat_ID('hidePost');
$myrecentposts = get_posts(array('post_not_in' => get_option('sticky_posts'), 'cat' => "-$cat,-$cathidePost",'showposts' => $count-of-posts));
$myrecentposts2 = get_posts(array('post_not_in' => get_option('sticky_posts'), 'cat' => "-$cat,-$cathidePost",'showposts' => -1));
$myrecentpostscount = count($myrecentposts2);
if ($myrecentpostscount > 0)
{ ?>
<div class="recentPosts"><h4><?php if ($myHeading !=="") { echo $myHeading; } else { echo "Recent Posts";} ?></h4><ul>
<?php
$current_page_recent = get_post( $current_page );
foreach($myrecentposts as $idxrecent=>$post) {
if($post->ID == $current_page_recent->ID)
{
$home_menu_recent = ' class="current_page_item';
}
else
{
$home_menu_recent = ' class="page_item';
}
$myclassrecent = ($idxrecent == count($myrecentposts) - 1 ? $home_menu_recent.' last"' : $home_menu_recent.'"');
?>
<li<?php echo $myclassrecent ?>><?php the_title(); ?></li>
<?php } ; if (($myrecentpostscount > $count-of-posts) && $count-of-posts > -1){ ?><li>View All Posts</li><?php } ?></ul></div>
Don't take this the wrong way. I'm not going to solve your memory problem at all in this answer. I will post another answer with a reason I believe you could have the mem problem The following is just a suggestion I hope you take as helpful: You have so much html jumbled in between your layout logic it is going to take you 3x as long to do figure out what is breaking and why.
Following the principles of refactoring I'm going to give one example and show how you can clean this up to the point where you can actually debug it yourself.
I'm taking this section of code to refactor a bit:
if ($myrecentpostscount > 0)
{ ?>
<div class="recentPosts"><h4><?php if ($myHeading !=="") { echo $myHeading; } else `{ echo "Recent Posts";} ?></h4><ul>`
First, pull the logic out of the template display (reformat for readability at the same time:
if ($myrecentpostscount > 0)
{
if ($myHeading !=="")
{
$displayHeading = $myHeading;
}
else
{
$displayHeading = "Recent Posts";
}
?>
Second, replace temporary variables with function calls [$myHeading]
/**
* This function determines if a heading is null, and returns the default if it is.
*/
function getDisplayHeading($customHeading)
{
if ($customHeading == "")
{
return "Recent Posts";
}
return $customHeading;
}
if ($myrecentpostscount > 0)
{
?>
<div class="recentPosts"><h4>
<?php echo getDisplayHeading($myHeading); ?></h4><ul>
Now finally, when you have all your logic at the top of the page, you can profile each function to see how much memory it uses and at which point too much memory is used in your page request. I'm going to post another answer to try to help there though, because I believe I have an idea.
In your code, you do the following thing:
$myrecentposts = get_posts(array('post_not_in' => get_option('sticky_posts'), 'cat' => "-$cat,-$cathidePost",'showposts' => $count-of-posts));
$myrecentposts2 = get_posts(array('post_not_in' => get_option('sticky_posts'), 'cat' => "-$cat,-$cathidePost",'showposts' => -1));
$myrecentpostscount = count($myrecentposts2);
You are actually fetching all of the posts, then counting them in code... I don't have the source of the "get_posts" function, but I would bet about 10 bucks that if you create a new function called "get_post_count" that doesn't fetch all the posts into the page, but rather does something like a "select count(*)" and gives you 1 result, you will eliminate your memory prob. If you post the body of your get_posts function we can probably help determine the easiest way to make a get_post_count function.
When you see the Allowed memory size of exhausted, is usually means that you have an endless loop on your hands. Check to make sure there are parameters to stop it from looping forever.

Categories