www.webdeveloper.com
Page 1 of 2 12 LastLast
Results 1 to 15 of 20

Thread: [RESOLVED] Caeser cipher help - excluding non-alphabetic characters

  1. #1
    Join Date
    Jan 2014
    Location
    Boston, Massachusetts
    Posts
    66

    resolved [RESOLVED] Caeser cipher help - excluding non-alphabetic characters

    Hey everyone,

    I wrote a Caesar cipher (a script where, given a message, the letters in the message are shifter x number of places; e.g. A => D, B => E, C => F, X => A, Y => B, Z => C, etc.). It works but it shifts all ASCII characters. I want to exclude characters that are not A-Z or a-z (outside the ASCII values of 65 - 90 and/or 97 - 122) so that spaces, punctuation, numbers all remain the same instead of shifting as well.

    The script is here:

    PHP Code:
    <?php
    for ($i=0$i strlen($string); $i++) {
        
    $ascii ord($string[$i]);
        for (
    $j=0$j $sp$j++) {
            if (
    $ascii == 90) { //uppercase bound
                
    $ascii 65//reset back to 'A' 
            

            else if (
    $ascii == 122) { //lowercase bound
                
    $ascii 97//reset back to 'a' 
            

            else {
                
    $ascii++;
            }
        }
        
    $newstring[$i] = chr($ascii);
        
    $encstring $newstring;
    }
    ?>
    Any help would be appreciated as I can't figure it out. If you want to see it in action it's here.

  2. #2
    Join Date
    Aug 2004
    Location
    Ankh-Morpork
    Posts
    19,407
    Sounds like you just need to change the else to an elseif, and put in that range as the condition?
    "Please give us a simple answer, so that we don't have to think, because if we think, we might find answers that don't fit the way we want the world to be."
    ~ Terry Pratchett in Nation

    eBookworm.us

  3. #3
    Join Date
    Jan 2014
    Location
    Boston, Massachusetts
    Posts
    66
    I replaced the last else with else if as follows:

    PHP Code:
    I changed the last else to else if as follows:

    else if (
    $ascii 65 || ($ascii 90 || $ascii 97) || $ascii 122 ) { //uppercase bound
                
                
    $ascii++;
            } 
    but it still isn't working. I can't seem to wrap my head around it. Any ideas?

  4. #4
    Join Date
    Aug 2004
    Location
    Ankh-Morpork
    Posts
    19,407
    PHP Code:
    esleif ( ($ascii >= 65 and $ascii <= 90) or ($ascii >= 97 or $ascii <= 122 ) ) { 
    PS: Feel free to change "and" to "&&" and "or" to "||", I just use the word forms out of habit, as I find them a bit easier both to read and type.
    "Please give us a simple answer, so that we don't have to think, because if we think, we might find answers that don't fit the way we want the world to be."
    ~ Terry Pratchett in Nation

    eBookworm.us

  5. #5
    Join Date
    Jan 2014
    Location
    Boston, Massachusetts
    Posts
    66
    As soon as I saw this I got excited, but I tried it and it still is shifting non-alphabetic characters such as space, period, exclamation point, etc.

    Here's what I have:

    PHP Code:
    for ($i=0$i strlen($string); $i++) {
        
    $ascii ord($string[$i]);
        for (
    $j=0$j $sp$j++) {
            if (
    $ascii == 90) { //uppercase bound
                
    $ascii 65//reset back to 'A' 
            

            else if (
    $ascii == 122) { //lowercase bound
                
    $ascii 97//reset back to 'a' 
            

            else if ( (
    $ascii >= 65 && $ascii <= 90) || ($ascii >= 97 || $ascii <= 122 ) ) {
                
    $ascii++;
            }
        }
        
    $newstring[$i] = chr($ascii);
        
    $encstring $newstring;

    I can't figure out where the problem lies; it seems like this should work. I seriously appreciate all your help on this, by the way! =)

  6. #6
    Join Date
    Aug 2004
    Location
    Ankh-Morpork
    Posts
    19,407
    Here's my revamped stab at it:
    PHP Code:
    <?php

    $sp 
    5;
    $string "Testing 1, 2, 3, and X, y, Z. All done!";
    $newstring = array();
    for (
    $i=0$i strlen($string); $i++) {
        
    $ascii ord($string[$i]);
        if (
    $ascii 65 || ($ascii 90 && $ascii 97) || $ascii 122) {
            
    $newstring[$i] = $string[$i];
        }
        else {
            for (
    $j=0$j $sp$j++) {
                
    $ascii += 1;
                if (
    $ascii == 91 or $ascii == 123) {
                    
    $ascii -= 26;
                }
            }
            
    $newstring[$i] = chr($ascii);
        }
    }
    $encstring implode(''$newstring);
    echo 
    $encstring;
    You do realize this would be extremely easy to decipher, right?
    "Please give us a simple answer, so that we don't have to think, because if we think, we might find answers that don't fit the way we want the world to be."
    ~ Terry Pratchett in Nation

    eBookworm.us

  7. #7
    Join Date
    Jan 2014
    Location
    Boston, Massachusetts
    Posts
    66
    So very close! I changed $sp = $_POST['offset']; and $string to $_POST['msg']; as that's where the user-entered info comes from.

    I entered "hi bill" into the form and on Encode it printed 3 different values: "lm fmpplm fmpp" into the textarea box, "Array" into the Encoded message output at the bottom, and "lm fmpp" where nothing should be printing. It looks like somehow it printed the decoded message twice (i.e. lm fmpp once and lm fmpp again[lm fmpplm fmpp]).

    Firebug shows the proper string as follows:

    Code:
    <form class="form-inline" method="post" role="form">
    lm fmpp
    <p>Original message:</p>
    So it's somehow printing in between the form and 'Original message' paragraph. Any clue what's going on?

  8. #8
    Join Date
    Jan 2014
    Location
    Boston, Massachusetts
    Posts
    66
    Sorry; it's printing here:

    HTML Code:
    </form>
    lm fmpp
    <p>Original message:</p>

  9. #9
    Join Date
    Aug 2004
    Location
    Ankh-Morpork
    Posts
    19,407
    Without seeing the code, no way to tell why it's outputting what it does where it does.
    "Please give us a simple answer, so that we don't have to think, because if we think, we might find answers that don't fit the way we want the world to be."
    ~ Terry Pratchett in Nation

    eBookworm.us

  10. #10
    Join Date
    Jan 2014
    Location
    Boston, Massachusetts
    Posts
    66
    I thought this was going to be a one-reply answer; I always end up with weird things going on.. haha.

    From index.php

    Code:
    <form class="form-inline" role="form" method="post">
    						<div class="table-responsive">
    						<table>
    							<tr class="tr_top">
    								<td class="td_top"><textarea class="form-control" rows="4" name="msg" placeholder="Your message here." onfocus='this.select()'><?php
    										require ('encode.php');
    										require ('decode.php');
    
    										if (isset($_POST['encode'])) {
    											echo $encstring;
    										} elseif (isset($_POST['decode'])) {
    											echo $decstring;
    										}
    									?></textarea></td>
    							</tr>
    							<tr class="tr_mid">
    								<td class="td_mid"><input type=text class="form-control input_mid" name="offset" value="<?php if (isset($_POST['encode']) || isset($_POST['decode'])) { echo htmlspecialchars($_POST['offset']);} ?>" placeholder="Enter a number." pattern="[0-9]{0,3}" oninvalid="setCustomValidity('Please enter a number between 1 and 999.')" oninput="setCustomValidity('')"></td>
    							</tr>
    							<tr class="tr_bottom">
    								<td class="td_bottom">
    									<input class="input_bottom btn btn-default submit" type="submit" name="encode" value="Encode">
    									<input class="input_bottom btn btn-default submit" type="submit" name="decode" value="Decode">
    									<input class="input_bottom btn btn-default" type="button" value="Clear"</td>
    							</tr>
    						</table>
    						</div><!-- close table-responsive -->
    					</form>
    
    				<?php
    				//encode
    				require ('encode.php');
    				if (isset($_POST['encode'])) {
    					echo "<p>Original message:</p>";
    					echo "<p class='string ital'>" . $string . "</p>";
    					echo "<p>Encoded message:</p>";
    					echo "<p class='string ital'>" . $newstring . "</p>";
    				}
    
    				//decode
    				require ('decode.php');
    				if (isset($_POST['decode'])) {
    					echo "<p>Encoded message:</p>";
    					echo "<p class='string ital'>" . $string . "</p>";
    					echo "<p>Decoded message:</p>";
    					echo "<p class='string ital'>" . $newstring . "</p>";
    				}
    				?>
    ---
    From encode.php

    PHP Code:
    <?php
    $sp 
    $_POST['offset'];
    $string $_POST['msg'];
    $newstring = array();
    for (
    $i=0$i strlen($string); $i++) {
        
    $ascii ord($string[$i]);
        if (
    $ascii 65 || ($ascii 90 && $ascii 97) || $ascii 122) {
            
    $newstring[$i] = $string[$i];
        }
        else {
            for (
    $j=0$j $sp$j++) {
                
    $ascii += 1;
                if (
    $ascii == 91 || $ascii == 123) {
                    
    $ascii -= 26;
                }
            }
            
    $newstring[$i] = chr($ascii);
        }
    }
    $encstring implode(''$newstring);
    echo 
    $encstring;
    ?>

  11. #11
    Join Date
    Aug 2004
    Location
    Ankh-Morpork
    Posts
    19,407
    Remove the echo command at the end of the encode file, and in the main file, use $encstring, not $newstring.

    In fact, the way you are modularizing things (which is good) could be taken a step further, and putting the encode/decode stuff into functions that return the resulting strings, which you then would call in the main file; or even (gasp!) a class definition with encode() and decode() methods.
    "Please give us a simple answer, so that we don't have to think, because if we think, we might find answers that don't fit the way we want the world to be."
    ~ Terry Pratchett in Nation

    eBookworm.us

  12. #12
    Join Date
    Aug 2004
    Location
    Ankh-Morpork
    Posts
    19,407
    In fact, here's how you might put it all into a single function, so that we can enforce the DRY (don't repeat yourself) principle:
    PHP Code:
    <?php
    /**
     * pseudo encrypt/decrypt a string
     * @return string
     * @param  string $string text to be encoded/decoded
     * @param  int    $offset number of positions to offset letters (only)
     */
    function caesar_cipher($string$offset)
    {
        if(!
    ctype_digit($offset)) {
            throw new 
    Exception("offset must be an integer");
        }
        
    $newstring = array();
        for (
    $i=0$i strlen($string); $i++) {
            
    $ascii ord($string[$i]);
            if (
    $ascii 65 || ($ascii 90 && $ascii 97) || $ascii 122) {
                
    $newstring[$i] = $string[$i];
            }
            else {
                for (
    $j=0$j abs($offset); $j++) {
                    
    $ascii += 1;
                    if(
    $offset and ($ascii == 91 or $ascii == 123)) {
                        
    $ascii -= 26;
                    }
                    elseif(
    $ascii == 65 or $ascii == 97) { // negative offset
                        
    $ascii += 26;
                    }
                }
                
    $newstring[$i] = chr($ascii);
            }
        }
        
    $encstring implode(''$newstring);
        return 
    $encstring;
    }
    To use it, just require() the file with that function definition, and then:
    PHP Code:
    $string "whatever...";
    $sp 5;
    $encrypted caesar_encrypt($string$sp);
    $decrypted caesar_encrypt($string$sp * -1); // just negate the original offset 
    "Please give us a simple answer, so that we don't have to think, because if we think, we might find answers that don't fit the way we want the world to be."
    ~ Terry Pratchett in Nation

    eBookworm.us

  13. #13
    Join Date
    Aug 2004
    Location
    Ankh-Morpork
    Posts
    19,407
    There's a bug in the above function, which is corrected in the following, where I decided to get all object-oriented on it:
    PHP Code:
    <?php

    /**
     * Provide a simple pseudo encryption of text only affecting [A-Za-z]
     */
    class CaesarCipher
    {
        
    /**
         * Encrypt it
         * @return string
         * @param  string $string
         * @param  int    $offset
         */
        
    public function encrypt($string$offset)
        {
            return 
    $this->execute($string$offset);
        }

        
    /**
         * Decrypt it
         * @return string
         * @param  string $string
         * @param  int    $offset
         */
        
    public function decrypt($string$offset)
        {
            return 
    $this->execute($string$offset * -1);
        }

        
    /**
         * pseudo encrypt/decrypt a string
         * @return string
         * @param  string $string text to be encoded/decoded
         * @param  int    $offset number of positions to offset letters (only)
         */
        
    private function execute($string$offset)
        {
            if(!
    is_int($offset)) {
                throw new 
    Exception("offset must be an integer");
            }
            
    // need to use this to fix bug:
            
    $inc 1;
            if(
    $offset 0) {
                
    $inc = -1;
            }
            
    $newstring = array();
            for (
    $i=0$i strlen($string); $i++) {
                
    $ascii ord($string[$i]);
                if (
    $ascii 65 || ($ascii 90 && $ascii 97) || $ascii 122) {
                    
    $newstring[$i] = $string[$i];
                }
                else {
                    for (
    $j=0$j abs($offset); $j++) {
                        
    $ascii += $inc;
                        if(
    $offset and ($ascii == 91 or $ascii == 123)) {
                            
    $ascii -= 26;
                        }
                        elseif(
    $ascii == 64 or $ascii == 96) { // negative offset
                            
    $ascii += 26;
                        }
                    }
                    
    $newstring[$i] = chr($ascii);
                }
            }
            return 
    implode(''$newstring);
        }
    }
    sample usage:
    PHP Code:
    $text "ABCDE, abcde, UVWXYZ, uvwxyz, 123.";
    $sp 4;
    $crypt = new CaesarCipher();
    echo 
    "<p>Start:<br />$text</p>\n";
    $text $crypt->encrypt($text$sp);
    echo 
    "<p>Encrypted:<br />$text</p>\n";
    $text $crypt->decrypt($text$sp);
    echo 
    "<p>Decrypted:<br />$text</p>\n"
    Test output:
    Start:
    ABCDE, abcde, UVWXYZ, uvwxyz, 123.

    Encrypted:
    EFGHI, efghi, YZABCD, yzabcd, 123.

    Decrypted:
    ABCDE, abcde, UVWXYZ, uvwxyz, 123.
    Last edited by NogDog; 02-02-2014 at 02:21 AM.
    "Please give us a simple answer, so that we don't have to think, because if we think, we might find answers that don't fit the way we want the world to be."
    ~ Terry Pratchett in Nation

    eBookworm.us

  14. #14
    Join Date
    Jan 2014
    Location
    Boston, Massachusetts
    Posts
    66
    NogDog, this is way above and beyond man. Thanks! I'm going to try to make it all work together with the Object Oriented version.

    One last question. As-is, everything works except for decode (decode.php). Here's what I have:

    PHP Code:
    <?php
    $sp 
    $_POST['offset'];
    $string $_POST['msg'];
    $newstring = array();
    for (
    $i=0$i strlen($string); $i++) {
        
    $ascii ord($string[$i]);
        if (
    $ascii 65 || ($ascii 90 && $ascii 97) || $ascii 122) {
            
    $newstring[$i] = $string[$i];
        }
        else {
            for (
    $j=0$j $sp$j++) {
                
    $ascii += 1;
                if (
    $ascii == 91 || $ascii == 123) {
                    
    $ascii -= 26;
                }
            }
            
    $newstring[$i] = chr($ascii);
        }
    }
    $decstring implode(''$newstring);
    ?>
    How do I get it to work the other way around? I tried $i--, $ascii -= 1, and $ascii += 26 in various combinations. $ascii -= 1 seemed to work the closest, but for my test case, I typed "Hi, bob!" with an offset of 4, and the encode function worked perfectly. The first time I use Decode it works; it decodes "Lm, fsf!" back to "Hi, bob!". But if I hit Decode again, it prints "De, ^k^!".

    When all this is said and done, I owe you a drink of your choice!

  15. #15
    Join Date
    Aug 2004
    Location
    Ankh-Morpork
    Posts
    19,407
    You want to do $ascii -= 1 to decrement $ascii, but then you need to use += 26 if it goes below the minimum value. (You could use $ascii-- or even --$ascii, but for readability/maintainability reasons, I prefer to avoid those.)
    Last edited by NogDog; 02-02-2014 at 10:56 AM.
    "Please give us a simple answer, so that we don't have to think, because if we think, we might find answers that don't fit the way we want the world to be."
    ~ Terry Pratchett in Nation

    eBookworm.us

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
HTML5 Development Center



Recent Articles