0

I'm trying to make a notification system, so far I made the notification text (poor one) and the active notifications (again, poor one)

Notification system is based on 4 notifications, each on MySql database in INT mode. They can be set to 0 (No notification) or 1 (yes notification and it will show an already made text by me.)

ActiveNotification system is based on sum of notifications. Not1+Not2+Not3+No4. Exemple: If 3 active not it shows 3.

What I want to do and will do:

I will create an admin section where it will be a "notification1 / Notification 2 / Notification 3 / Notification 4" form and there I will put 1 or 0, depends which notification.

I will create (somehow) $Session user when click "a href" his notification to be set at 0, all of them.

But I want to do an easy and BETTER way if there exists on. But I don't know how or imagine, because never worked with things like that.

Is there (certainly is) a BETTER WAY how can I modify my script and achieve what I want? (I know that StackOverFlow doesn't talk about ideas, that's why I'm posting my code.)

Legend

Notificare 1 = First Notification row
Notificare 2 = Second Notification row
Notificare 4 = Last and fourth notification Row
Notificari = How many Notifications are set to 1. (it shows active notifications)
TN1 = Date of when first notification arrived
TN4 = Date of when fourth and last notification arrived

PHP

   <?php
        session_start(); //starting session
        include("config.php"); //including our config.php  
        error_reporting(E_ALL); 

        if(isset($_SESSION['username'])) //if session is set, so if user is logged in... 
        { 
            $username = $_SESSION['username']; //setting variable username as one from session 
            $query = mysql_query("SELECT * FROM users WHERE username = '$username'"); 
            while($row = mysql_fetch_assoc($query)) //looping thousgt table to get informations 
        { 
$Notificare1 = $row['Notificare1'];
        $Notificare2 = $row['Notificare2'];
        $Notificare3 = $row['Notificare3'];
        $Notificare4 = $row['Notificare4'];
        $TN1 = $row['TN1'];
        $TN2 = $row['TN2'];
        $TN3 = $row['TN3'];
        $TN4 = $row['TN4'];

    if($Notificare1 == 1) {
            $Notificare1 = "<li><a href='settings.php'>
            <div class='user_img'><img src='images/logo.png' alt=''></div>
            <div class='notification_desc'>
            <h6>Title</h6>
             <p>Trebuie să-ți schimbi setările contului!<br> Fă-o chiar acum apăsănd pe mine.</p>
            <p><span> Primit la: $TN1 </span></p>
            </div>";}
            if($Notificare2 == 0) {
            $Notificare2 = "<li></li>";}
            if($Notificare2 == 1) {
            $Notificare2 = "<li><a href='#subdomenii'>
    <div class='user_img'><img src='images/logo.png' alt=''></div>
     <div class='notification_desc'>
     <h6>EminDesign.ro</h6>
    <p>Cererea ta de subdomeniu a fost acti<br>vat! Click pe mine.</p>
    <p><span> Primit la: $TN2 </span></p> </div>";}


    ($Notificare3    == 0) {
    $Notificare3 = "<li></li>";}
    if($Notificare3 == 1) {
    $Notificare3 = "<li><a href='#facturi'>
   <div class='user_img'><img src='images/logo.png' alt=''></div>
    <div class='notification_desc'>
    <h6>EminDesign.ro</h6>
    <p>Cererea ta de design a fost acti<br>vat! Click pe mine..</p>
    <p><span> Primit la: $TN3 </span></p>
    </div>";}

    if($Notificare4  == 0) {
            $Notificare4 = "<li>/li>";}
            if($Notificare4 == 1) {
            $Notificare4 = "<li><a href='#restante'>
                                <div class='user_img'><img src='images/logo.png' alt=''></div>
    <div class='notification_desc'>
    <h6>Title</h6>
    <p>Ai o factură neplătită ! Click pe mine.</p>
    <p><span> Primit la: $TN4 </span></p>
    </div>";}
    $Notificari = $row['Notificare1'] + $row['Notificare2'] + $row['Notificare3']+ $row['Notificare4'];
    }?>

and HTML

<li class="dropdown head-dpdn">
    <a href="#" class="dropdown-toggle" data-toggle="dropdown" aria-expanded="true"><i class="fa fa-bell-o" aria-hidden="true"></i> <span class="badge blue"><?php echo $Notificari ?></span></a>
    <ul class="dropdown-menu">
        <li>
            <div class="notification_header">
                <h3>Your Notifications</h3>
            </div>
        </li>
        <?php echo $Notificare1 ?>
        <?php echo $Notificare2 ?>

        <?php echo $Notificare3 ?>

        <?php echo $Notificare4 ?>

         <li>
            <div class="notification_bottom">
                <a href="#">Delete notifications</a>

            </div> 
        </li>
    </ul>
</li>

////

if($Text1 == 100) {
        $TotalA == 1;}
if($Text2 == 100) {
        $TotalB == 1;}
if($Text3 == 100) {
        $TotalC == 1;}
if($Text4 == 100) {
        $TotalD == 1;}
$Progres = $row['TotalA'] + $row['TotalB'] + $row['TotalC'] + $row['TotalD'];

TotalA,B,C,D are not defined.

3
  • 2
    session_start MUST be written before any output, most developers will recommend that it is your first line of code. Please stop using mysql_ functions; upgrade to mysqli. Please improve your code tabbing for improved readability and debugging. Rather than 1 and 0 values, you may enjoy the benefits of bitmask values: 1, 2, 4, 8. Then you can store all notification data as a single number in a single column. Please read the bottom of this answer: stackoverflow.com/a/49256146/2943403 Commented Mar 31, 2018 at 9:30
  • @mickmackusa modified with improved readibility. Well, I tried to make it without 1 and 0 values, but i don't know how else, as I said, new on this things and at forum where i've read it shown something like this code. Commented Mar 31, 2018 at 9:40
  • For your update, that's pretty simple. See my update. Commented Mar 31, 2018 at 10:30

1 Answer 1

2

Bitwise?

This is a somewhat hard subject. But if you ever used a FLAG in PHP then you used a bitwise number. eg. error_reporting(E_ALL)

Basically what they do is compare the binary value of the number. Which probably makes no sense to you. So I will give you an example. Currently you have 4 boolean values, they are 0 or 1 and require several fields etc. So with a bitwise value you would have this:

notification1 = 1
notification2 = 2
notification3 = 4
notification4 = 8
// notification5 = 16

Now as you can see the value doubles for each one. The reason for this can be explained with some simple math (without getting into the whole 0000001, 0000010 thing).

1+2 = 3  //3 is not 4
1+2+4 = 7 //7 is not 8
1+2+4+8 = 15 // 15 is not 16

Right, so each previous set of numbers must not add up to the next number.

The point of all this is that with the PHP bitwise operators, we can use a single field and tell which of the 4 bits is set in it.

So if user has all notifications on 1-4. Their value is 15 or 1|2|4|8. To check if they have notification 1 turned on, you would do this (with a single & ):

if(1 & 15) echo "true";

Outputs

true

Now, if you wanted to set just 2 say notification 1 and 4. You would do this:

$note_1 = 1;
$note_2 = 2;
$note_3 = 4;
$note_4 = 8;

$mysettings = $note_1|$note_4; //=9

Then we could check it like this:

if($mysettings & $note_1 ) //true
if($mysettings & $note_2 ) //false
if($mysettings & $note_3 ) //false
if($mysettings & $note_4 ) //true

Ok, so a few more examples to drive it home:

 if(1 & 1) //true
 if(1 & 2) //false
 if(1 & 4) //false

 if(1 & 7 ) //true  (1+2+4) or 1|2|4
 if(2 & 7 ) //true ...
 if(4 & 7 ) //true ...

So what this does, is that instead of 4 boolean values we have to store, now we have one integer value that we can tell which of the 4 booleans were set.

Therefore, besides doing some basic arithmetic, it would be possible to elimiate having 4 separate columns, 4 separate fields etc. This bubbles up throughout your code reducing the complexity. Also as a bonus, if you want to add a notification at a later time, you won't have to go though and copy a bunch of code and add another field to your database for the users setting. You can simply add the next double in (in this case 16).

Now UI wise, I would use a set of checkboxes each with one of the bit values. So a user would just check which notification they want and then we just add/subtract it in PHP and save that to one field. Or something similar (like a multi select) where they/you don't have to manually add the values in or try to remember that bit 32 was notification #6.

Also, you could set them as global constants using define

 if(!defined('NOTE_1')) define('NOTE_1', 1);
 if(!defined('NOTE_2')) define('NOTE_2', NOTE_1 * 2);  //1 * 2 = 2
 if(!defined('NOTE_3')) define('NOTE_3', NOTE_2 * 2);  //2 * 2 = 4
 if(!defined('NOTE_4')) define('NOTE_4', NOTE_3 * 2);  //4 * 2 = 8

then you can use them anywhere by simply doing this(assuming $mynotes was a thing):

//$mynotes = NOTE_1|NOTE_4; //9

if($mynotes & NOTE_1) //true

It's pretty slick, and I hope I didn't slaughter that definition of bitwise too much for you guys that know all about it. I was trying to keep it simple, and that is how I think of it as I don't think in binary to good.

Questions>?

UPDATE

For your unrelated question, which should be a separate question. But, as it's ridiculously simple I will indulge you this time.

So you have this.

if($Text1 == 100) {
    $TotalA == 1;
}

This part

$TotalA == 1;

Has 2 = which is comparison not assignment. Simply remove one of the =. It's actually perfectly valid in PHP to do comparison outside of an if statement. For example if you did (assuming you dont get an undefined variable error):

 var_dump($TotalA == 1);

It would say something like one of these two

 bool(true)
 bool(false)

You get the error, because doing comparison requires a read from the variable, which hasn't been set, because this was supposed to be doing the setting. But because, as I said, this is comparison -- there is no setting taking place.

UPDATE1

So back to the bitwise stuff... I wanted to show the effect this will have on your code. So taking just a small bit of your code (abbreviated):

$query = mysql_query("SELECT * FROM users WHERE username = '$username'"); 
while($row = mysql_fetch_assoc($query)){ 
    //uses 4 columns, if we need to add a notification we have to add another column and change this code.
    //more concerning is we would need to change the DB schema
    $Notificare1 = $row['Notificare1'];
    $Notificare2 = $row['Notificare2'];
    $Notificare3 = $row['Notificare3'];
    $Notificare4 = $row['Notificare4'];
    ....
    if($Notificare1 == 1) {
        $Notificare1 = "<li><a href='settings.php'>
        <div class='user_img'> ... ";
    }
    if($Notificare2 == 0){
       $Notificare2 = "<li></li>";
    }
    if($Notificare2 == 1) {
       $Notificare2 = "<li><a href='#subdomenii'> ...";
    }
 ...
 }

Doing the same thing with Bitwise (assuming we defined the constants that I outlined above):

$query = mysql_query("SELECT * FROM users WHERE username = '$username'"); 
while($row = mysql_fetch_assoc($query)){ 
    //uses 1 column, if we add another notification then no changes are required here.
    $Notificare = $row['Notificare'];
    ...
    if($Notificare & NOTE_1) {
        $Notificare1 = "<li><a href='settings.php'>
            <div class='user_img'> ... ";
    }
    if($Notificare & NOTE_2){
        $Notificare2 = "<li></li>";
    }else{ //changed the if to an else, if it's not true it must be false.
        $Notificare2 = "<li><a href='#subdomenii'> ...";
    }
    ...
}

SQL Queries. MySql has its own equivalent set of bitwise operators. You can view the documentation for those here. These work pretty much the same what as they do in PHP. So you can do this:

$sql = 'SELECT count(id) as count FROM users WHERE Notificare & '.NOTE_1; //constants are one of the few things I would say is safe to concatenate in a query as they are immutable.

So this would give you the number of users that have Notification #1 set.

PARTING NOTES

I noticed two other pretty big issues, both dealing with your SQL query

 mysql_query("SELECT * FROM users WHERE username = '$username'");

Firstly the mysql_* set of functions are depreciated as of PHPv5.6 (I think) and removed as of PHPv7 (I know for sure). So you will want to use a different database driver. I suggest using PDO instead of MySqli, I haven't used MySqli for about 4 years (in production code), and I haven't missed it. I may be a bit biased on it.

Secondly concatenating variables into SQL leaves you with SQLInjection vulnerabilities. This is were an attacker inserts some SQL of their own into the query. An example would be where $username = "'; DROP TABLE users; --". So putting it into your SQL we get something like this (please don't run it)

 SELECT * FROM users WHERE username = ''; DROP TABLE users; --' // using -- is the start of a line comment in SQL, so anything after that is ignored..

Which would run the first query and then Drop(delete) the table. This is a bad example because there are some settings that prevent running multiple queries, but they are not always configured correctly.

To prevent this, both PDO, and MySqli have Prepared Statements. You could also argue that the data comes from $_SESSION so it must be clean, but where did it get put in there from? It's hard to tell. So Prepared Statements are designed to be used near the Point Of Failure, or where the query is executed. So we can clearly see that the query is safe without having to dig through files and files to check where that data came from.

But as this post is long enough I will leave that discussion for another time. I would feel remiss if I didn't point those 2 issues out.

Sign up to request clarification or add additional context in comments.

8 Comments

+1 for nice explanation! I learned something very helpful. I won't divulge how many 0 and 1 I have used:).
Yea, it took me quite some time to understand it myself. But it can be quite powerful.
+! too, explained better than school. But, a question. How can I make an echo which shows how many "100" are in Cell1, Cell2, Cell3. If there are 3 of 100, shows 3. If there are only 2 it shows 2
Ex: Cell 1 = random. Cell 2 = random. Cell 3 = 100. It will echo 1. Cell 1 = 100 Cell 2 = 100 Cell 3= random. It will echo 2 Cell 1 = 100. Cell 2 = 100. Cell 3 = 100. It will echo 3.
i.imgur.com/99UnfQj.png I have 4 rows. Each number (1% to 100%) is set from Mysql. In the top of the page, at that red circle, I want to echo how many values are 100. (Currently, it should echo 3) but I don't know how to check how many values are 100. i.imgur.com/plYWs6d.png
|

Your Answer

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