4
\$\begingroup\$

I made a website last night that allows people to sync HTML5 <video>s (playing/pausing). The way it does this is by using Ajax to run a MySQL query every 2 seconds to check if anyone has paused the video. Depending on the response, it plays/pauses it. If someone plays/pauses the video, it calls a page through Ajax to update the database.

This is the page that plays the video and manages the syncing:

<!DOCTYPE HTML>
<html>
    <head>
        <meta name="viewport" content="width=device-width">
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
    </head>
    <body>
    <?php
        require('/connect/streaming.php'); //On this page: $con = mysqli_connect(host, user, pass, database)
        $query = "SELECT link FROM vids WHERE vidKey = ?";
        $stmt = mysqli_stmt_init($con);
        $stmt->prepare($query);
        $stmt->bind_param('s', $_GET['id']);
        $stmt->execute();
        $resultFirst = $stmt->get_result();
        $result = mysqli_fetch_assoc($resultFirst);
    ?>
        <video controls autoplay name="media" id="vid">
            <source src="<?php echo $result['link']; ?>" type="video/<?php echo $_GET['type']; ?>">
        </video><br>
        <a onclick="flipCheck()" id="checkA">Click here to disable checks</a>
        <script>
            var checking = true;
            function flipCheck() {
                if (checking) {
                    checking = false;
                    $("#checkA").html("Click here to enable checks");
                }
                else {
                    checking = true;
                    $("#checkA").html("Click here to disable checks");
                }
            }
            //Pause video on load
            $(document).ready(function() {
              var vid = document.getElementById("vid"); 
              vid.pause();
            });

            //Every second, check what others are doing
            window.setInterval(function(){
              request({'type': 'get', 'vidId': <?php echo $_GET['id']; ?> });
            }, 2000);

            //On play, tell the server
            vid.onplaying = function() {
                request({'type': 'update', 'vidId': <?php echo $_GET['id']; ?>, 'timestamp': vid.currentTime, 'status': 'playing' });
            };

            //On pause, tell the server
            vid.onpause = function() {
                request({'type': 'update', 'vidId': <?php echo $_GET['id']; ?>, 'timestamp': vid.currentTime, 'status': 'paused' });
            };

            //Function to request data
            function request(funcData) {
                if (checking) {
                    $.ajax(
                    {
                        url: "https://chipperyman.com/streaming/process.php", 
                        type: "GET",
                        dataType: 'json',
                        data: funcData,
                        success: function(result){
                            console.log(result);
                            if (result['msg'] == 'paused') {
                                vid.pause();
                                vid.currentTime = result['timestamp'];
                            }
                            else if (result['msg'] == 'playing') {
                                if (vid.paused) {
                                    vid.currentTime = result['timestamp'];
                                    vid.play();
                                }
                            }
                    }}); 
                }
            }
        </script> 
    </body>
</html>

This is the page that manages the Ajax calls:

<?php
//MySQL
require('/connect/streaming.php'); //On this page: $con = mysqli_connect(host, user, pass, database)
//Setup checkArgs
function checkArgs(){
    $args = func_get_args();
    foreach ($args as $arg){
        if (!isset($_GET[$arg])) {
            die(json_encode(array('response' => 'error', "msg" => "Missing args")));
        }
    }
}

//Check for type and vidId
checkArgs('type', 'vidId');
//If we're updating 
if ($_GET['type'] == 'update') {
    checkArgs('timestamp', 'status');
    $query = "UPDATE vids SET timestamp = ?, status = ? WHERE vidKey = ?";
    $stmt = mysqli_stmt_init($con);
    $stmt->prepare($query);
    $stmt->bind_param('dsi', $_GET['timestamp'], $_GET['status'], $_GET['vidId']);
    $stmt->execute();
    $response = array("response" => "success", "msg" => "Preformed action.");
}
else if ($_GET['type'] == 'get') {
    $query = "SELECT * FROM vids WHERE vidKey = ?";
    $stmt = mysqli_stmt_init($con);
    $stmt->prepare($query);
    $stmt->bind_param('i', $_GET['vidId']);
    $stmt->execute();
    $resultFirst = $stmt->get_result();
    $result = mysqli_fetch_assoc($resultFirst);
    $response = array("response" => "success", "msg" => $result['status'], "timestamp" => $result['timestamp']);
}
else {
    $response = array("response" => "error", "msg" => "Invalid type argument");
}
echo json_encode($response);

This is the database layout:

MySQL Database Layout

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

I'm not that familiar with the HTML5 video tag, so I will not say anything about that.

Your code is open to reflected XSS here: <?php echo $_GET['id']; ?> (inside script tags).

You might also think about extracting some code blocks to functions to increase readability and reduce duplication. For example you have SELECT * FROM vids WHERE vidKey = ? twice, which amounts to quite a lot of duplication (oddly, you one use s and once i). A function like getVideoByKey might be helpful here.

\$\endgroup\$
2
  • \$\begingroup\$ In .htaccess there's a script that strips tags from all GET and POST tags. I will work on the second part, thank you. \$\endgroup\$
    – Jon
    Oct 29, 2015 at 22:11
  • \$\begingroup\$ @Chipperyman filtering tags is not enough against XSS, as the user input is echoed inside script tags. \$\endgroup\$
    – tim
    Oct 30, 2015 at 11:45

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.