1

I was just wondering if it is possible to remove a value from an external .txt file once it is randomly chosen.

// Opens file with key values
$randomkeys = file('keys.txt');

// Takes keys from file and puts it into an array
$random_keys = array_rand($randomkeys, 2);

// Outputs the random key chosen
echo "Your code is: ";
echo $randomkeys[$random_keys[0]];

This is the code I am currently using and it works by reading the file that includes all the keys and then it is put into an array that would later be shown to the user that is using the site.

Screenshot of keys.txt file contents

What I want to add to this is that when the user views the site that the key shown to them will be removed from the list so no one else can get that same key.

Jordan H.
  • 59
  • 1
  • 7
  • 1
    don't bother. start using a database. –  Sep 22 '16 at 23:01
  • Just remove the line from the text file after showing it here's an example: http://stackoverflow.com/questions/1377279/find-a-line-in-a-file-and-remove-it – ivan Sep 22 '16 at 23:01
  • Generate the key at the time one is requested. Why would you pre store them in a file. What happens when you remove the last key from the file and another user wants one. – RiggsFolly Sep 22 '16 at 23:02
  • The file IO is slow so if multiple people are accessing the file (that needs to be continuously rewritten) at the same time, you will have a complete mess on your hands. Do as @RiggsFolly suggests, generate them on request. You can then store the used keys in a database for lookup, if you don't want the same key to be used more than once. – M. Eriksson Sep 22 '16 at 23:41
  • @MagnusEriksson see the thing is I need to show the user a code that works for another program as the code can only be used once. So basically the file will have lets say 100 keys that have been generated and put into the text file, I then need PHP to display one of those keys and then remove it from the list. – Jordan H. Sep 23 '16 at 14:58

2 Answers2

1

Simply best solution is to use RDBMS.

But if You insist on solution with .txt file:

unset($randomkeys[$random_keys[0]]);
array_values($randomkeys);
file_put_contents('keys.txt', implode("\n", $randomkeys));

but keep in mind that in situation of asynchronous access it can keep the key that was used (because of parallel write) - so it's better to use DB.

Or just have another file: used_keys.txt and append used key to the bottom.

so solution:

$keys = file('keys.txt'); // reads keys file
$used_keys = file('used_keys.txt'); // reads used keys file
$keys = array_values(array_diff($keys, $used_keys)); // returns array of unused keys
$key = $keys[mt_rand(0, sizeof($keys)-1)]; // picks random key

// outputs random key
echo "Your code is: ";
echo $key;

// appends used random key to the end of used keys file
file_put_contents('used_keys.txt', $key, FILE_APPEND);
num8er
  • 18,604
  • 3
  • 43
  • 57
0

You could use file_get_contents to pull the data in the file, str_replace to remove the line and file_put_contents to put the data back. As suggested in this answer:

How to delete a line from the file with php?

Although this might not be the most efficient way of doing that, you could end up reading from and writing from the disk a lot depending on your application. Ideally you'd use a database like MySQL or SQLite.

Edit 9/25/2016

Here's a simple implementation of a database that might work for you. As of PHP 5.3 SQLite3 is enabled by default. This method generates a new code when you need instead of pre generating a list. Of course you could pre generate a list using this method as well if you wanted to.

PHP Docs: http://php.net/manual/en/book.sqlite3.php

You only need a few concepts to get going:

  • SQLite3::open [Create or Open a database file]
  • SQLite3::query [For Selects]
  • SQLite3::querySingle [For Selects]
  • SQLite3::exec [For Insert, create, delete, update]

Note: My method for generating the "Code" is not cryptographically secure. If security is a big concern See: PHP: How to generate a random, unique, alphanumeric string?

Setup.php

Run this file once to create your database, you can delete it after if you like

<?php
class MyDB extends SQLite3
{
    function __construct()
    {
        $this->open('mysqlitedb.db');
    }
}

$db = new MyDB();

$db->exec('CREATE TABLE codes (code_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,code varchar(50) NOT NULL)');

$db->close();

CodeManager.php

Include this file anywhere you want to generate or delete a code

<?php

class CodeManager extends SQLite3
{
    function __construct()
    {
        // You can change this to the file location of the code list.
        $this->open('mysqlitedb.db');
    }

    function getRandomCode()
    {
        do {
            // If users have a unique identifier, you can use it instead of rand()
            // This should guarrantee a unique value that doesn't have to be checked first.
            // You can also replace md5(...) with any method you prefer to generate the code
            $code = md5(uniqid(rand(), true));

            $code_check = $this->querySingle('SELECT code FROM codes WHERE code="'.$code.'"');

        } while(!is_null($code_check)); // Need this loop as long as we are using rand()

        // Try to add the code to the list of used codes
        if($this->exec('INSERT INTO codes (code) VALUES ("'.$code.'")'))
            return $code;

        return false;
    }

    function deleteCode($to_delete)
    {
        // Try to delete the record
        if($this->exec('DELETE FROM codes WHERE code="'.$to_delete.'"'))
                return true;

        // If we couldn't delete the record
        return false;
    }

    function getAllCodes()
    {
        $all_codes = array();
        $results = $this->query("SELECT * FROM codes");

        while ($row = $results->fetchArray()) {
                $all_codes[] = $row['code'];
        }

        return $all_codes;
    }
}

App.php

Example of how to use CodeManager.php

<?php

include('CodeManager.php');

$cm = new CodeManager();

// Get a single new code
$new_code = $cm->getRandomCode();
echo $new_code."\r\n";

// Get a list of all codes generated so far
$all = $cm->getAllCodes();

// Display them one by one
foreach($all as $single){
    echo $single . "\r\n";
}

?>
Community
  • 1
  • 1
Arnolio
  • 502
  • 3
  • 8
  • Basically I want to try and not have to use a database as I want to keep it very simple and so that when a user visits the page they will then copy and code use it and it will be taken out of the file so that someone else doesn't get a code that doesn't work, I could have had the array within the same file however I wanted to make it simple so that more codes can be added when the amount of codes are limited – Jordan H. Sep 23 '16 at 14:34
  • I hear you, but implementing a simple database in PHP doesn't have to be too much harder than coding the file solution. Check out the update to my answer. – Arnolio Sep 26 '16 at 01:50