broj1 356 Humble servant Featured Poster

Now the searchApp.php. You first have to check if all the conditions, passed over by ajax call, exist. Then you escape the values, to be safe. Next you construct the query without any conditions. Then you check if any of conditions exist and add WHERE and AND statements. In this case we have only one possible condition: the category. You can do a bit of error checking too, I have left it out for clarity. See the comments in the code.

<?php

// the database connection has to be setup here (the link has to exist)!
require_once '../connect.php';

// check if all the conditions exist
// (for now check only for search_term and category, later add other drop downs)
if(
    isset($_POST['search_term']) && 
    !empty($_POST['search_term']) &&
    isset($_POST['category'])  
  ) {

    $search_term = mysql_real_escape_string($_POST['search_term']);
    $category = mysql_real_escape_string($_POST['category']);

    // construct the query for all categories first
    $query = "SELECT Type FROM autosuggest WHERE Type LIKE '$search_term%'";

    // then if category is other than all add the condition
    if($category != 'all') {

        $query .= " AND Category LIKE '$category'";
    }

    // die($query);

    $resource = mysql_query($query);

    while(($row=mysql_fetch_assoc($resource))) {

        echo '<li><b>',$row['Type'],'</b></li>';
    }
}

?>
broj1 356 Humble servant Featured Poster

OK, I had a quick look and fortunately spotted the errors soon enough to reply tonight. I will reply in several posts since it is going to be a lot of code

The script in the Primary.js should post over to the searchApp.php also the category (and other dropdown values) not just the value of the input box. You need category to filter the data from DB in the query. I named the variable with data conditions in the code below (also see the comments in the code).

$(document).ready(function() {

    $('.autosuggest').keyup(function () {

        var search_term = $(this).attr('value');

        // read the values of the select elements (drop downs)

        // read the value of category 
        var category=$('#category').attr('value');

        // this is the conditions you will post over to the searchApp.php script
        // assembled here for clarity
        var conditions = {

            'search_term' : search_term,
            'category' : category
        }; 

        // just for debugging
        // alert(conditions.toSource());

        // post the conditions over to the searchApp.php script
        $.post('ajax/searchApp.php', conditions, function(data) {

            //alert(data);
            $('.result').html(data);

            /*
            // you can sort this out yourself

            $('.result li').click(function() {

                var result_value=$(this).text();
                $('.autosuggest').attr('value',result_value);
                $('.result').html('');

            });
            */

        });
    });
});

This script works fine and sends object with conditions to searchApp.php, which I will explain in next post.

P.S. You can enhance this code so that ajax post will get launched only after say 3 characters have been typed in. This is how many autosuggesters work, they do not fire on the first character due to a possibility of large result sets returned.

broj1 356 Humble servant Featured Poster

Just sent you a PM. Otherwise just click on my name (broj1). You will see my profile. Click on contact me button.

broj1 356 Humble servant Featured Poster

Can you send me all your scripts in question, database structure and data on PM. You can send me the table structure and data as an SQL statement (go to phpmyadmin and export the table in sql format).

broj1 356 Humble servant Featured Poster

Tis is how I did it and it proved to be a good concept. I have defined access levels which were integers. The higher the level (value) the higher the privileges.
Between each level I had a space for new levels if I need them later. The access level is saved in the user database for each user.

access_level | description
--------------------------
         220 | application admin (developes only)
         200 | contents admin
         180 | system admin
         100 | regular user (edit, view)
          60 | viewer (view)
           0 | no access

As you can see I use unsigned integer for access level so it does not take much space in db. I have plenty of room below and above the range and also between access levels which proved good tactics since I had to add levels already. The access level gets stored in the session during login so all I have to do is to compare it with required level on the beginning of each page:

// example for checking a system admin's access level
if(!isset($_SESSION['access_level']) || $_SESSION['access_level'] < 180) {
    header('location: logout.php');
}

In the above example only system admin and higher levels can access the page.

I also define constants to make the code more readable:

define('ACCESS_LVL_APPADMIN', 220);
define('ACCESS_LVL_CONTADMIN', 200);
define('ACCESS_LVL_SYSADMIN', 180);
define('ACCESS_LVL_REGUSER', 100);
define('ACCESS_LVL_VIEWER', 60);
define('ACCESS_LVL_NOACCESS', 0);

// example for checking a system admin's access level
if(!isset($_SESSION['access_level']) || 
   $_SESSION['access_level'] < ACCESS_LVL_SYSADMIN) {
    header('location: logout.php');
}
broj1 356 Humble servant Featured Poster

In line 4 in above snippet you misspelled category (you left out letter g):

$("#cateory").change(function(){
broj1 356 Humble servant Featured Poster

And browse this site. It is a lot of information but it is not a bad idea to become familiar with most of it.

broj1 356 Humble servant Featured Poster

If I understand the thing after revising your code you wish to have a functionality that will display suggestions upon typing in an input box and based on selection in dropdowns. This is quite a complex task which involves ajax calls fired on each keypress while you are in the input box. jquery has functionalities ready for that but still you have to do customization since you have additional selections.

The javascript logic is not in the posted code and I guess it is in the primaryapp.js, which is included with script tags. But this case is quite hard to debug since all the javascript should be posted, the db tables should be posted (structure and contents) and the php and html scripts should be examined. I can not promise you that I can do that quickly.

Meanwhile see here for nice tutorials how to do the autosuggest feature.

I hope someone with experience with this will be also able to contribute.

broj1 356 Humble servant Featured Poster

Check the query. Insert this code right after line 5:

die($sql);

It is a simple debugging technique. It will display the query and you can inspect it and test it in phpmyadmin. You can also post it here.

broj1 356 Humble servant Featured Poster

You do quite a lot of building checkbox code with concatenation of string and with all the quotes you have to take care of you can quickly miss one and the browser won't render correctly. Have you checked the html source (in Firefox: right click on page -> View page source - the possible erros in html code are colored red)?

I prefer this style of constructing HTML code with PHP:

echo"<input type='checkbox' id='c{$checkcount}' name='c{$checkcount}' checked='true' value='true'/>";

I am using PHP's ability to parse variables within quoted strings (curly braces are optional in this case, I used them for clarity). With this style of coding errors are less likely to occur.

Edit: The same goes for constructing queries. The following code is more readable:

$sql="select * from student where ClassId='$c' and RollNo>='$sr' and RollNo<='$er'";
broj1 356 Humble servant Featured Poster

You are not saying much :-). Can you please explain what and how is not working well (what you expect v.s. what comes out, error messages).

$visitortimezone=("$tmzone, ($stz)");

Seems like a function name is missing here? What you intended to do?

broj1 356 Humble servant Featured Poster

Classes are part of Object Oriented Programming concept (OOP). PHP first supported only traditional procedural programming style but with version 5 (and partly four) the OOP functionality was added. It has been mature for quite some time now and many functions have both versions (i.e. mysqli_query).

The benefit of OOP approach (or classes as you say) is easier maintenance, upgrading and better scalability of complex applications but provided that you design your classes appropriately. This takes practice to achieve. There is another benefit of being familiar with OOP in that many libraries and frameworks use OOP approach and it is good if you understand it well.

broj1 356 Humble servant Featured Poster

OK, so the category is not comming through. Can you post the code for the form (to check the select).

broj1 356 Humble servant Featured Poster

But category is obviously not in the $_POST. Can you put this line in the very beginning of the script and post the result:

die(print_r($_POST, 1));

This will print the contents of the $_POST array and stop the script.

broj1 356 Humble servant Featured Poster

Yo check for search term before issuing the query but you do not check for Category. Is this OK? Is category not mandatory to have a value?

if(isset($_POST['search_term'])==true && empty($_POST['search_term'])==false)
broj1 356 Humble servant Featured Poster

As you can see there is no value for the Category in the query. Is this OK?

broj1 356 Humble servant Featured Poster

There is a backtick just before the AND that should not be there. Remove it (and comment out the die statement) then try it out.

broj1 356 Humble servant Featured Poster

Looks like there is still an error in the query. Can you add this line of code just after line 6:

    die("SELECT `Category`, `Type` FROM `autosuggest` WHERE `Category`='{$_POST[category]}'` AND `Type` LIKE '$search_term%'");

As you see it will display the constructed query. Can you please post it here.

You can also copy the displayed query and test it in phpmyadmin.

broj1 356 Humble servant Featured Poster

What is the error? Can you please post the newest version of the code?

broj1 356 Humble servant Featured Poster

What exactly would you like to show for VisitTime and VisitorTimeZone? I can guess the timezones can be counted something like:

$tzQuery = 'SELECT VisitorTimeZone, COUNT(*) AS tz_count 
            FROM visitslog GROUP BY VisitorTimeZone';
broj1 356 Humble servant Featured Poster

Where do you do any calculations for the chart especially for the values in question? If you want to know what is good library for drawing charts I highly recommend jQplot.

broj1 356 Humble servant Featured Poster

I have just noticed that you posted the structure and contents of the tables in your post, sory. You are missing the namn column in the po table. You are referring to the namn column in the while loop.

And as Biiim said, associative indexes (keys) are case sensitive while mysql names are not. I would strongly suggest that you use always lowercase to avoid confusion. Also chose table names and field names carefully and make them descriptive for the same reason.

broj1 356 Humble servant Featured Poster

There are two other small errors in the code:

  • remove <br> tags after </td> tags since they should not be there
  • remove // combo box text from HTML code (it is not a comment within a php block)
broj1 356 Humble servant Featured Poster

Do you have a column namn in the PO table? You are referring to it in the while loop:

echo '<option value="'.$item['po'].'">'.$item['namn'].'</option>';
broj1 356 Humble servant Featured Poster

In most cases you need to declare a primary key (unique field) in a table so you can address particular records. If your data already has a field that is unique (such as social security number in the USA or enrollment number on universities) then you can use that, but you have to be sure it is unique (no two records can have the same value). If you haven't got such a field in your data then you usually let database create it for you by using autoincrement type of the field.

broj1 356 Humble servant Featured Poster

Did you maybe forget to declare the ID colums Autoincrement? That way you can leave the id values out and db will autogenerate them.

Edit: sory pritaeas, posted just seconds after you did :-)

LastMitch commented: Thanks for the explanation! +9
broj1 356 Humble servant Featured Poster

This is mysterious. The code in the snippet you posted seem to be OK (once corrected with suggestions from other posts). Can you post the whole code? I would have to test it in my environment to try to find something.

broj1 356 Humble servant Featured Poster

In the URL you can't use quotes as far as I know. Spaces should be encoded:

http://domain.com/Customer.php?customer_name=John+Doe

or

http://domain.com/Customer.php?customer_name=John%20Doe

I am not sure which encoding scheme is more correct, anyone else knows? Anyway the form should take care of that or urlencode php function.

broj1 356 Humble servant Featured Poster

As far as I understood the question he wants to display data about a particular user. The user is defined in the querystring ?customer_name=John+Doe. So you can get cuustomer name from the $_GET array where variables from query string are stored. You have to use this info in the query to filter out the record with appropriate data.

Where the querystring comes from I do not know since it was not posted. It could be dropdown box or input box etc.

So it has nothing with rewriting with the URL?

I am not saying that. I haven't checked your proposal for solution. As far as I know rewriting the URL makes URLs look nicer, easier to bookmark, easier to get read by search engines etc.

broj1 356 Humble servant Featured Poster

You have to add a WHERE clause to the query:

// first check if a querystring exists at all (avoiding errors)
if(isset($_GET['customer_name'])) {

    // escape the value form the url (security)
    $customer_name = mysql_real_escape_string($_GET['customer_name']);
    // then use the value in WHERE statement
    $sql="SELECT id,customer_name FROM Customers WHERE customer_name='$customer_name'";
}

And consider using mysqli instead of mysql.

broj1 356 Humble servant Featured Poster

The $query variable does not contain a valid resource since there is an error in the query. You can not perform a concatenation within a double quoted string. Correct the query this way: remove the . and enclose the array element $_POST[category] in curly braces). I also changed && to AND since I am not sure whether && is valid in mysql. Also a backtick was missing after the Category.

$query=mysql_query("SELECT `Category`, `Type` FROM `autosuggest` WHERE `Category`='{$_POST[category]}'` AND `Type` LIKE '$search_term%'");

The name of the $query variable is missleading since it contains a resource not a query. I would change it to $resource.

$resource=mysql_query("SELECT `Category`, `Type` FROM `autosuggest` WHERE `Category`='{$_POST[category]}'` AND `Type` LIKE '$search_term%'");

while($row=mysql_fetch_assoc($resource))
{
    echo '<li><b>',$row['Type'],'</b></li>';
}

And as bradly.spicer said switch to newer mysqli instead of older mysql, when possible.

broj1 356 Humble servant Featured Poster

One more thing: if password is incorrect, do not tell that to the user; if username is incorrect, do not tell that to the user. Allways tell them that login failed, but not the reason. This way you give no clue to potential attacker.

broj1 356 Humble servant Featured Poster

This is tricky.

What you get when you run this query in phpmyadmin:

SELECT * FROM PO ORDER BY PO ASC
broj1 356 Humble servant Featured Poster

Escaping values using mysql_real_escape_string or similar (i.e. mysqli_real_escape_string) function greatly minimizes a possibility of sql injection by escaping dangerous characters. Some other things you have to do are (not a comprehensive list):

  • put quotes arround any query parameters - even numbers
  • or use prepared statements, but this method is slightly less efficient
  • validate input values (if you expect a number check it with is_numeric, if you expect an integer within known range check for the range, check strings for maximum lenght, whitelist values if possible)

Also use newer mysqli extension instead of old mysql which might soon get deprecated.

More on this topic is here and here.

And more on login security.

broj1 356 Humble servant Featured Poster

Sory it should be:

echo '<option value="'.$item['po'].'">' . $item['namn'] . '</option>';

My error when copying.

broj1 356 Humble servant Featured Poster

You should temporary remove the isSelected($item['po'],$batch) function and see if you get anything:

while ($item = mysql_fetch_assoc($result))
{
    echo '<option value="'.$item['po'].'" . $item['namn'] . '</option>';
}

The isSelected() function probably only adds selected="selected" to selected option.

broj1 356 Humble servant Featured Poster

<b>Fatal error</b>: Call to undefined function isSelected() in <b>C:\xampp\htdocs\Innovation\script_shop\stock.php</b> on line <b>48</b><br />

This is probably the answer: the isSelected() function that you are calling, does not exist. Have you included appropriate file where the function should be defined?

And also

Undefined index: po in <b>C:\xampp\htdocs\Innovation\script_shop\stock.php

means that there are no records since nothing exists in the $item array.

broj1 356 Humble servant Featured Poster

As long as this is not a higly confidential banking or government site this might be enough. Hopefully you have done the password hashing as per good practices. You might want to check this link.

Other aspect of security is input data validation/sanitization (username and password) to prevent sql injections.

broj1 356 Humble servant Featured Poster

Happy to hear that :-)

broj1 356 Humble servant Featured Poster

As cereal said run the query:

SELECT * FROM PO ORDER BY PO ASC

in phpmyadmin (or mysql client) and see if you get the correct resultset for options in your select. If the query returns correct result then check the html code (in Firefox right click -> View page source) and check whether there are no html errors also.

You might want to check whether isSelected($item['po'],$batch) function returns correct value.

broj1 356 Humble servant Featured Poster

I am not sure whether I understood your question correctly but here we go: Setting an action attribute to another page is not a bad practice and I do not think it causes a lot of workload for the server. But you can have the action attribute set to the same page if you wish. In that case you have to check if the form was submitted on the beginning of the page. If yes, then you have to act appropriately (delete the record, redirect or display a message or whatever). But in your current case You have to check whether the query is OK so I suggest you do a little debugging. Change the deleteuserform.php page sligtly like this:

<?php
// this line is only for debugging, you will remove it later
die("Delete FROM Customers WHERE id = {$data['id']}");
mysql_query("Delete FROM Customers WHERE id = {$data['id']}");
?>

Now when you select an option from the drop down you will be redirected to the second page but the query will only get displayed and not executed. You can examine it and copy it to phpmyadmin and test it there.

I also suggest you state the form method explicitly to POST which is more appropriate for deleting.

<form action="deleteuserform.php" method="post">
bradly.spicer commented: Great Help! +2
broj1 356 Humble servant Featured Poster

As TonyG said put a closing php tag on line 14 in above code.

broj1 356 Humble servant Featured Poster

On top of each page that uses session variables you have to put:

session_start();

It looks like it's missing on page 2.

broj1 356 Humble servant Featured Poster

The same goes for the password variable.

broj1 356 Humble servant Featured Poster

Enclose $data['id'] in curly braces since it is a complex variable so PHP knows what variable to parse from this string.

mysql_query("Delete FROM Customers WHERE id = {$data['id']}");

See this link.

broj1 356 Humble servant Featured Poster

As simple as:

$search = $_SESSION['search'];

$_SESSION['search'] is already a string since it came from the form input. You can use it in a query but make sure you at least escape it first:

$query = "SELECT * FROM tablename WHERE somefield LIKE '%" . mysqli_real_escape_string($search) . "'";
broj1 356 Humble servant Featured Poster

Echoing should work in most cases if you put echo in correct place which can be sometimes tricky. Take in account included files and functions, ajax calls etc. And have all error reporting enabled while you are debugging.

There is also a comprehensive debug tool called xdebug. I have never used it but have seen some demos and it seems that might be what you are after. But I think it requires a little bit of learnig to start using it.

broj1 356 Humble servant Featured Poster

More or less guessing:

On line 276 (reply code) you have:

$model_quote = printInvoice("Residential - Curbside/Garage", "S5-E", 119, $qts5e, $s5e_quote_residence, $total);

Shouldn't it be:

$model_quote = $model_quote . printInvoice("Residential - Curbside/Garage", "S5-E", 119, $qts5e, $s5e_quote_residence, $total);

Seems like you are loosing all previous information here. But I might be wrong since it is hard to figure this out from this amount of code.

broj1 356 Humble servant Featured Poster

Maybe a word or two also on a poor man's debugging technique. When you quickly want to examine values of variables you just insert an echo or die statement after the point in code that interests you. When examining simple values (strings, integer, floats...) just use echo (or die if you also want to stop the execution). If you want to examine arrays or objects then you add a little bit of formatting and use print_r function (with second parameter set to 1 to use the output in echo):

$myArray = array('key1' => 'value1', 'key2' => 'value12);
echo '<pre>' . print_r($myArray, 1) . '</pre>';

You can also send output into html code only in a form of a html comment:

echo '<!-- ' . print_r($myVar, 1) . ' -->';

This way the debug output won't interfere with displayed page, it will be included in source code of the page only (in Firefox then you just right click and select View page source).

broj1 356 Humble servant Featured Poster

This link might help you a bit.