Jump to content

Barand

Moderators
  • Posts

    24,425
  • Joined

  • Last visited

  • Days Won

    806

Posts posted by Barand

  1. If you want to show a gallery then, yes, you really want thumbnail size images to display. You can have an image that is originally 4000 pixels x 2500 pixels and shrink it in the html image tag by specifying width='200' height = '125' so it looks like a thumbnail but you are still transferring the multi MB file. You therefore need to run a job to create thumbnail versions of all your images. (The best time to create them is when the image is uploaded but too late for that now).

    Perhaps have an images folder with the original images and a thumbs folder to contain the thumbnail images, one for each original)

    When you create the thumb images, decide on the size of square into which they should fit (say 150 or 200 pixels). Then calculate the thumbsize so the longest dimension just fits that square (be it landscape or portrait) then calculate what the shorter dimension needs to be to maintain the same aspect ratio. Then you just copy/resize the image to the new file.

  2. I also can't understand  why your array index values are limited to a single signed byte. I'd expect a maximum of at least 2 billion (memory permitting)

    Array
    (
        [2147483647] => 1
    )

    or even this on a 64 bit system

    Array
    (
        [9223372036854775807] => 1
    )

     

  3. 4 minutes ago, Nigel12 said:

    I then uploaded there score to the database

    Don't store totals in a database, store the individual records that make up that total. That way you have an audit trail. With the responses, you can get info on which questions a user got right or wrong, which is lot more useful that just knowing how many. When you want the scores, just count the correct responses.

  4. Running your readdir() code on one of my folders, with 528 files, loads all of them into the array.

    Last bit of my var_dump...

      [524]=>
      string(9) "xmlns.php"
      [525]=>
      string(15) "xmltestdata.xml"
      [526]=>
      string(11) "YMDdiff.php"
      [527]=>
      string(10) "zodiac.txt"
    }

     

  5. You could've had a database set up in less time than you spent moaning about what a PITA it is.

    It takes about half a dozen statements to create an image table from your image directory.

    JFDI.

    const IMGDIR = 'images/';
    
    $db->exec("CREATE TABLE IF NOT EXISTS `image_lib` (
                  `img_id` int(11) NOT NULL AUTO_INCREMENT,
                  `name` varchar(100) DEFAULT NULL,
                  `path` varchar(255) DEFAULT NULL,
                  `width` int(11) DEFAULT NULL,
                  `height` int(11) DEFAULT NULL,
                  `mime_type` varchar(20) DEFAULT NULL,
                  `description` varchar(255) DEFAULT NULL,
                  `img_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
                  PRIMARY KEY (`img_id`),
                  FULLTEXT KEY `idx_image_lib_description` (`description`)
                )
                ");
    
    $ins = $db->prepare("INSERT INTO image_lib (name, path, width, height, mime_type) VALUES (?,?,?,?,?)") ;
    $imgs = glob(IMGDIR.'{*.png,*.jpg}', GLOB_BRACE);
    foreach ($imgs as $i) {
        $s = getimagesize($i);
        $ins->execute( [
                        basename($i),
                        IMGDIR,
                        $s[0],
                        $s[1],
                        $s['mime']
                       ]);
    }

    Job done!

    • Like 1
  6. Are you not storing the users' answers anywhere?

    Write a record to the "user_response" table when a user answers a question. Then you have a record of which questions each user has answered.

    Only select questions for a user where there is no record in the response table for that question.

    SELECT  Question
          , Answer1
          , Answer2
          , Answer3
          , CorrectAnswer
    FROM question q 
           LEFT JOIN
         user_response r ON q.id = r.q_id
    WHERE r.q_id IS NULL
    ORDER BY RAND()
    LIMIT 1  
    +-----------+                              +-----------+
    |  user     |                              | question  |
    +-----------+                              +-----------+
    | user_id   |--+                      +----| id        |
    | name      |  |                      |    | question  |
    +-----------+  |                      |    | etc       |
                   |                      |    +-----------+
                   |                      |
                   |   +---------------+  |
                   |   | user_response |  |
                   |   +---------------+  |
                   |   | q_id          |>-+
                   +--<| user_id       |
                       | test_date     |
                       | answer        |
                       +---------------+
    

     

    • Like 1
  7. 39 minutes ago, SaranacLake said:

    as data entry in phpMyAdmin is a PITA!

    Anything with phpMyAdmin is a PITA. There are alternatives

    • MySQL Workbench
    • Write a php script for your data entry.

    (You can create the initial db table by scanning the directory then you just need to add the descriptions. You can then easily give the users a facility to search the image descriptions for keywords)

  8. This example uses glob() to get all .png and .jpg in a folder. By default, the folder is assumed to be named "images" and is a subdirectory of the folder containing the script.

    Images are displayed as thumbnails, 5 in each row with 25 per page.

    <?php
    session_start();
    
    const IMGDIR = 'images/';
    const PERPAGE = 25;
    
    $page = $_GET['page'] ?? 1;
    $imgdir = $_GET['dir'] ?? IMGDIR;
    
    if (!isset($_SESSION['imgdir']) || $_SESSION['imgdir'] != $imgdir) {
        unset($_SESSION['images']);
        $_SESSION['imgdir'] = $imgdir;
        $page = 1;
    }
    if (!isset($_SESSION['images'])) {
        $_SESSION['images'] = glob($imgdir.'{*.png,*.jpg}', GLOB_BRACE);     // get .jpg and .png images
    }
    $total = count($_SESSION['images']);
    
    /** **************************************************************************************
    * display paginated images from SESSION['images]
    * 
    * @param int $page
    * @param int $perpage
    */
        function displayImages($page, $perpage)
        {
            $start = ($page - 1) * $perpage;
            $ilist = array_slice($_SESSION['images'], $start, $perpage);
            foreach ($ilist as $i) {
                $n = trim(basename($i));
                list($iw, $ih,, $sz) = getimagesize($i);
                if ($iw >= $ih) {                                                    // landscape
                    $w = 150;
                    $h = 150 * $ih/$iw;
                } else {                                                             // portrait
                    $h = 150;
                    $w = 150 * $iw/$ih;
                }
                $alt = substr($n, 0, 15);
                echo "
                      <div class='image'>
                          <img src='$i' height='$h' width = '$w' alt='$alt'>
                      </div>
                    ";
            }
            echo "<div style='clear:both'></div>";
        }
    
    /** ************************************************************************************
    * function to output page selection buttons
    *                     
    * @param int $total   total records
    * @param int $page    current page number
    * @return string      selection buttons html
    */
        function page_selector($total, $page)
        {
            if ($total==0) {
                return '';
            }
            $kPages = ceil($total/PERPAGE);
            $filler = '&nbsp;&middot;&nbsp;&middot;&nbsp;&middot;&nbsp;';
            $lim1 = max(1, $page-2);
            $lim2 = min($kPages, $page+3);
            $p = $page==1 ? 1 : $page - 1;
            $n = $page== $kPages ? $kPages : $page + 1;;
            $out = "$kPages page" . ($kPages==1 ? '' : 's') . " &emsp;";
            if ($kPages==1) {
                return $out;
            }
            $out .= ($page > 1) ? "<div class='pagipage' data-pn='$p'>Prev</div>&ensp;" : "<div class='pagipage x' data-pn='$p' disabled>Prev</div>&ensp;";
            if ($page > 4) {
                $out .= "<div class='pagipage' data-pn='1'>1</div> $filler";
            }
            elseif ($page==4) {
                $out .= "<div class='pagipage' data-pn='1'>1</div>";
            } 
            for ($i=$lim1; $i<=$lim2; $i++) {
                if ($page==$i)
                    $out .= "<div class='pagicurrent'>$i</div>";
                else
                    $out .= "<div class='pagipage' data-pn='$i'>$i</div>";
            }
            if ($page < $kPages-3) {
                $out .= "$filler <div class='pagipage' data-pn='$kPages'>$kPages</div>";
            }
            $out .= $page < $kPages ? "&ensp;<div class='pagipage' data-pn='$n'>Next</div>" : "&ensp;<div class='pagipage x' data-pn='$n' disabled>Next</div>";
            return $out;
        }
    
    ?>
    <!DOCTYPE html>
    <html>
    <head>
    <meta http-equiv="content-language" content="en">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <meta name="author" content="B A Andrew">
    <meta name="creation-date" content="11/29/2019">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <title>Example</title>
    <script type="text/javascript">
    $().ready( function() {
        
          $(".pagipage").click( function() {
              $("#page").val( $(this).data("pn") )
              $("#form1").submit()
          })
    })
    </script>
    <style type="text/css">
    
        body            { font-family: verdana, sans-serif; font-size: 11pt; }
        label           { display: inline-block; width: 150px; font-weight: 600; }
        #image_wrapper  { margin: 30px; }
        .image          { width: 18%; min-height: 200px; margin: 10px; float: left; text-align: center; padding: auto;}
        /* pagination styles */
        .pagipage       { display: inline; width: 25px; height: 15px; padding: 3px 5px; text-align: center; font-size: 9pt;
                          border: 1px solid #BB9A21 ; color: #BB9A21; background-color: #FFF; cursor: pointer; margin-left: -1px; }
        .pagipage.x     { background-color: #CCC;}
        .pagipage:hover { background-color: #BB9A21; border-color: #F0F; color: white; }
        .pagicurrent    { display: inline; width: 25px; height: 15px; text-align: center; font-size: 9pt; font-weight: 600;
                          border: 1px solid #BB9A21; background-color: #BB9A21; color: white; padding: 3px 5px; }
        .paginate_panel { text-align: center; margin: 20px 0; width: 100%; color: #BB9A21; }
    
    </style>
    </head>
    <body>
    <header>
        <h1>Example Image List</h1>
    </header>
    <form id="form1">
    <fieldset>
        <label>Image Folder</label>
        <input type="text" name="dir" value="<?=$imgdir?>" size="80">
        <input type="hidden" name="page" id="page" value="<?=$page?>">
        <br>
        <label>&nbsp;</label>
        <input type="submit" name="btnSubmit" value="Submit">
    </fieldset>
    </form>
    <div class='paginate_panel'>
        <?=page_selector($total, $page, PERPAGE)?>
    </div>
    <div id="image_wrapper">
        <?=displayImages($page, PERPAGE)?>
    </div>
    <div class='paginate_panel'>
        <?=page_selector($total, $page, PERPAGE)?>
    </div>
    </body>
    </html>

     

    • Like 1
    • Great Answer 1
  9. Nothing to do with version of PHP. The problem is with variable scope.

    You need to pass the variable to the function, same as you have with $ip.

     

    foreach($ranges as $key => $value){
            if($key<=$code){
                if($ranges[$key][0]>=$code){$two_letter_country_code=$ranges[$key][1];break;}
                }
        }

    On closer reading, the variable is defined in the loop, but only if the two conditions are true. Otherwise it is undefined.

    Define it as 

    $two_letter_country_code = '';

    before the foreach loop;

  10. If you look up GROUP_CONCAT in the MySQL manual...

    The result is truncated to the maximum length that is given by the group_concat_max_len system variable, which has a default value of 1024. The value can be set higher, although the effective maximum length of the return value is constrained by the value of max_allowed_packet. The syntax to change the value of group_concat_max_len at runtime is as follows, where val is an unsigned integer:

    SET [GLOBAL | SESSION] group_concat_max_len = val;

     

    • Thanks 1
  11. Or you could take the view that the product is a timeslot. If they want part of one and part of the next then they buy both.

    Check which slots contain or over lap the required times as this example does (see line 40) ...

    <?php
    
    $business_hours = [
                         1 => [ 'am_from' => '10:00',  'am_to' => '12:00',  'pm_from' => '13:00',  'pm_to' => '19:00' ],
                         2 => [ 'am_from' => '08:00',  'am_to' => '12:00',  'pm_from' => '13:00',  'pm_to' => '17:00' ],
                         3 => [ 'am_from' => '12:00', 'am_to' => '12:00', 'pm_from' => '13:00',  'pm_to' => '19:00' ],
                         4 => [ 'am_from' => '08:00',  'am_to' => '12:00',  'pm_from' => '13:00',  'pm_to' => '17:00' ],
                         5 => [ 'am_from' => '08:00',  'am_to' => '12:00',  'pm_from' => '13:00', 'pm_to' => '13:00' ],
                      ];
    //------------------------------------------------------------
    // from above array, generate daily 30 minute slots
    // for the next 15 days
    //
    $slots = [];
    $dt1 = new DateTime();
    $intwd = DateInterval::createFromDateString('next weekday');
    $dp_days = new DatePeriod($dt1, $intwd, 14);
    foreach ($dp_days as $d) {
        $dno = $d->format('w');
        $times = $business_hours[$dno];
        $slots[$d->format('Y-m-d')] = generateSlots($times);
    }
    
    //------------------------------------------------------------
    //  place these bookings in their slots
    //
    $bookings = [  ['title' => 'Test 1', 'start' => '2019-11-26 10:15', 'end' => '2019-11-26 11:30'],
                   ['title' => 'Test 2', 'start' => '2019-11-29 11:00', 'end' => '2019-11-29 12:00'],
                   ['title' => 'Test 3', 'start' => '2019-12-02 15:30', 'end' => '2019-12-02 16:30']
                ];
    
    foreach ($bookings as $b) {
        $sd = new DateTime($b['start']);
        $ed = new DateTime($b['end']);
        $date = $sd->format('Y-m-d');
        $st = $sd->format('H:i');
        $et = $ed->format('H:i');
        foreach ($slots[$date] as &$s) {
            if ($s['t'] != '') continue;                                   // not available
            if ($et > $s['s'] && $st < $s['e']) {                          // if booking is in or overlaps slot        ( LINE 40 )
                $s['t'] = $b['title'];                                     //          place title into slot
            }
        }
    }
    
    //------------------------------------------------------------
    //  output the slots to the page
    //
    $tdata = '';
    foreach ($slots as $d => $ddata) {
        if ((new DateTime($d))->format('w')==1) {
            $tdata .= "<tr><td colspan='12'> </td></tr>\n";
        }
        $tdata .= "<tr><td>" . date('D d M', strtotime($d)) . '</td>';
        foreach ($ddata as $slt) {
            switch ($slt['t']) {
                case 'closed': 
                    $cls = 'class="closed"';
                    $txt = ''; 
                    break;
                case '': 
                    $cls = ''; 
                    $txt = ''; 
                    break;
                default: 
                    $cls = 'class="booked"';
                    $txt = $slt['t']; 
            }
            $tdata .= "<td $cls>$txt</td>";
        }
        $tdata .= "</tr>\n";
    }
    
    /**
    * generate daily timeslots
    * 
    * @param array $times      - array of business hours for the day
    */
    function generateSlots($times)
    {
        $stime = '';
        $dt1 = new DateTime('08:00:00');
        $dt2 = new DateTime('19:00:00');
        $di = new DateInterval('PT1H');
        $dp = new DatePeriod($dt1, $di, $dt2);
        $slots = [];
        foreach ($dp as $t) {
            $k = $t->format('G');
            $h1 = $t->format('H:i');
            $h2 = $t->modify('+1 hour')->format('H:i');
            $text =  ($h1 >= $times['am_from']) && ($h1 < $times['am_to']) || ($h1 >= $times['pm_from']) && ($h1 < $times['pm_to']) ? '' : 'closed' ;
            $slots[$k] = [ 's'=>$h1, 'e'=>$h2, 't'=>$text];
        }
        return $slots;
    }
    ?>
    <!DOCTYPE html>
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>Example Bookings</title>
    <style type="text/css">
        body, table    { font-family: calibri, sans-serif; font-size: 11pt; }
        table          { border-collapse: collapse; width: 90%; margin: 0 auto; }
        th             { padding: 4px 2px; background-color: #006EFC; color: #FFF; border-color: #FFF;}
        td             { background-color: #FFF; padding: 2px; }
        td.closed      { background-color: #888; color: #FFF; }
        td.booked      { background-color: #FFC0C0; }
    </style>
    </head>
    <body>
    <header>
       <h1>Example Bookings</h1>
    </header>
    <table border='1'>
        <tr><th rowspan='2'>Date</th><th colspan='4'>AM</th><th></th><th colspan='6'>PM</th></tr>
        <tr><th>8 – 9</th><th>9 – 10</th><th>10 – 11</th><th>11 – 12</th>
            <th>12 – 1</th><th>1 – 2</th><th>2 – 3</th><th>3 – 4</th><th>4 – 5</th><th>5 – 6</th><th>6 – 7</th></tr>
        <?=$tdata?>
    </table>
    </body>
    </html>

     

    • Like 1
  12. Having run the above code, my phpinfo() in the same script shows

    image.png.b2564397eeff0472ee131e42d8438766.png

    However, the output from a second identical script was exactly the same - the default reverted to London time. So the "data.timezone" setting is the one used unless it is set in the script.

    Running phpinfo() in a separate script shows "London" for both.

    So, Yes. You would need it every script unless you set it at ini file level.

    • Thanks 1
  13. I have built apps for clients that use it and used it when testing. I don't send that many emails myself to know if there is a problem. Whether or not it gets thrown into the spam bucket is down to algorithms on the server rather than the software sending the mail. PHPMailer just makes things a lot easier, especially if you want to send attachments etc. (Every notification email that PHPFreaks sends to me ends up in in my spam even though Freaks domain  is in my contacts and I have specified "never block sender". For some reason they must look spammy.)

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.