Grow your CSS skills. Land your dream job.

Substring headaches

  • # November 14, 2012 at 2:44 am

    Hey yall,

    I’m writing a function.

    The parameter it takes is a string, with the anatomy of numbers in an increasing order, separated by periods. One such string might look like this:

    1.4.12.56

    With any number of numbers it wishes to have.

    Now, I also have an key-value array defined, in which the keys are integer values, which correspond to strings. for example:

    $array = array (
    1 => “oranges”,
    2 => “apples”,
    3 => “pears”
    );

    That is a very shortened version of my 63 key-value pairs long array. (And BTW, I wasn’t sure on this…it is valid to use integers as keys or must you use strings?)

    Anyway, now that we have the string and array, I am trying to write a function that takes the string, chops it up into pieces, which are divided by the periods, looks at the array, utilizes foreach (at least that’s what I’m thinking) to grab each value corresponding to the key, and make a new array full of the strings and return that.

    If I wasn’t clear enough,

    if I put in a string, 1.3, it should return me an array with the contents “oranges”, “pears”.

    I have written a function for coming from an array to this number sequence, to store it in the database, but I cannot reverse my own doing -_-

    I specifically got stuck on the chopping up the string…I don’t really know how to divide at periods, but I guessed it would be easy enough. (Maybe too much Jahooma’s Logicbox? :P) If I should be making the string input another format, please suggest. I’m open to ideas :)

    Thanks,
    Red

    # November 14, 2012 at 3:39 am

    Why are you using an integer key for the $array ? An array already has integer keys.
    sorry I didn’t notice it was posted in php and I thought you were speaking about js ($array, stupid me..), but you might be able to do pretty much the same thing with php

    http://jsfiddle.net/XmjRC/

    see here:

    http://php.net/manual/en/function.split.php

    # November 14, 2012 at 10:22 am

    http://pastebin.com/yxDrb5hR

    # November 14, 2012 at 11:24 am

    ⬑ good solution.

    Regarding integer keys, yes, it’s perfectly legal, and useful when you might need particular key values (instead of starting at `0`).

    # November 14, 2012 at 1:27 pm

    Thanks guys. I will look into these and see what comes out well :)

    # November 14, 2012 at 3:35 pm

    Ok guys…now I’m having trouble calling my first function that I managed to write myself, the function that takes an array, looks up its key, and makes the type of string aforementioned. Can anyone help look at this? The page doesn’t load at all when this function is called, but anytime else it will.

    function waresToNumbers($array) {
    $string = ”;
    foreach($array as $value) {
    if (substr($value, 0, 1) == “e”) {
    $value = deleteFirstLetter($value);
    $x = array_search($value, $wares);
    $x = $x*2;
    $string = $string.$x.”.”;
    } else {
    $value = deleteFirstLetter($value);
    $x = array_search($value, $wares);
    $string = $string.$x.”.”;
    }
    }
    $string = substr($string, 0, -1);
    return $string;
    }

    I am calling it like this:

    $sell = waresToNumbers($_POST);
    $buy = waresToNumber($_POST);

    Where selling and buying are arrays submitted via post form data.

    Last of all, deleteFirstLetter is what it sounds like, a simple substr function:

    function deleteFirstLetter($str) {
    return substr($str, 1);
    }

    EDIT: Now I’ve implemented MrSoundless’ function and calling that doesn’t load the page either. I have a feeling I’m calling the functions incorrectly…but how?

    # November 14, 2012 at 6:47 pm

    First:

    If your page is “not loading,” that probably means you have error reporting disabled. You should enable error reporting during development so you don’t have to guess at what’s going wrong.

    In your php.ini file, find these settings and comment them out (i.e., prepend them with a `;` – **do not** delete them, you’ll want to restore them when you’re done with your debugging):

    ;error_reporting = {this might be any of several values}
    ;display_errors = Off
    ;display_startup_errors = Off

    then give them these values:

    error_reporting = E_ALL
    display_errors = On
    display_startup_errors = On

    Next, the obvious problem with your function is that `$wares` does not exist.

    It’s also very difficult to figure out what you’re *trying* to do – your function seems to be very tightly related to the data structures you expect to receive. Can you show an example of what your arrays [are supposed to] look like?

    # November 15, 2012 at 11:15 am

    I did as told but still it doesn’t load. Chrome states “HTTP 500 Internal Server Error.” This is usually a problem with my syntax I’m pretty sure there is none.

    $wares does exist, it is my oranges apples grapes array. This is the reference array that says

    $wares = array(
    1 => “apples”,
    2 => “oranges”,
    3 => “pears”
    );

    etc. That’s not the real array but you get the idea. I want two functions:
    1. takes an array (just values array, no keys), cycles through them, finds their key in the $wares array, and appends it to a string. The wares are separated by a period. So you get a string like 1.4.28 that I can store in the database.
    2. takes the string from the database and reverts the string back to an array.

    Now that I think about it it might be cool to just put the straight forward ware names in the database, but that’s not as clean (i.e. oranges.apples.pears instead of 1.2.3)

    # November 15, 2012 at 9:36 pm

    > still it doesn’t load. Chrome states “HTTP 500 Internal Server Error.”

    some hosts are more zealous about hiding errors. Ask them about it. Also ask about where your error log file is; PHP errors should be being logged there.

    > $wares does exist, …

    Not in your function, it doesn’t.

    Read up about “scope” in PHP. Variable scope is, basically, the “space” within a script where variables “exist.” Classes and functions in PHP have their own scope. Example:

    < ?php

    $myvar = “some value”;
    # this is the “global scope.”
    # if you declare $myvar here,
    # it’s available anywhere in the global scope.

    if( condition ){
    # conditional blocks, loops, etc. don’t have their own scope
    # $myvar is available here.
    }

    function myfunc(){
    # functions *do* have their own scope -
    # $myvar does not exist here!

    $myvar = “other value”;
    # if you declare $myvar inside the function,
    # it **is not** the same as the $myvar in the global scope.
    print $myvar;
    # local (myfunc) scope – prints “other value”
    }
    print $myvar;
    # global scope – prints “some value”

    To use a global variable inside a function, you need to either pass it in (preferred), or import it from the global scope.

    < ?php

    # pass the variable you need into the function
    ## preferred ##
    function pass( $arg ){
    /* do stuff */
    }
    # when you pass $myvar to the function, like so -
    pass( $myvar );
    # it is available inside the function as “$arg”.

    # import the variable you need into the function
    function import_var(){
    global $myvar;
    # now the global $myvar is available inside the function.
    /* do stuff */
    }
    # this method is less preferable,
    # since you cannot be sure of the current state of the global $myvar
    # (or if it even exists when the function is called)

    > I want two functions: 1. takes an array (just values array, no keys), cycles through them, finds their key in the $wares array, and appends it to a string. The wares are separated by a period. So you get a string like 1.4.28 that I can store in the database. 2. takes the string from the database and reverts the string back to an array.

    Before going ahead with this, consider that you’re defeating the purpose of using a database by encoding a bunch of data and storing it in a single field – you’re effectively making it “invisible.”

    What if you wanted to find records of Oranges (“1″)? You’d have to extract all the data, convert it back into an array, and *then* search for Oranges. If you have a large dataset, that’s a huge waste of time. If you’d stored “Oranges” in the database directly, MySQL could’ve searched *for* you (that’s its purpose in life, after all).

    But anyway,

    If you want to represent an array as a string (e.g., so you can store it in the DB), there’s already a function to do that:

    < ?php
    $array = array( ‘oranges’,’apples’,’pears’ );

    # convert $array into a string value
    $str = serialize( $array );

    # now you can save it to the DB, in your SESSION, whatever
    # to convert it back, use:
    $array = unserialize( $str );

    # you can also use JSON -
    $jsonstr = json_encode( $array );

    # and convert it back into an array
    $array = json_decode( $jsonstr,true );

    # November 16, 2012 at 1:50 pm

    Obviously the reason I want to do it this way is unclear to you, but I believe it’s necessary. Allow me to explain a little more?

    There is a web based game I play. It is completely HTML CSS Ajax etc. It is a trading game, so there are different wares you can trade around for more money. For each of the 63 wares, there is an excellent variant, so you have a total of 126 unique wares to trade.

    Now this game, (called Remanum), is holding a contest for profile page design. I have designed my page so that user has an “edit” page, in which they can use checkboxes to say “I’m selling this” or “I’m buying this”. They have to check the wares they want specifically, that is, they may want the excellent version of a good or the regular one, or both. So one of the wares is iron, for example. The value of the excellent iron checkbox is “eiron”, so I’ve added an “e” to the beginning of each value for the checkboxes of excellent variants.

    Now when the browser receives the array of checkboxes, it should look up the ware’s key in the $wares array. I haven’t included the excellent wares as their own entries in the $wares array. If the first letter of the current array value is e, then you should delete the first letter, then look up the key of that ware, then take the key and 63, so that if 1 => “iron”, “eiron” will detect the first letter is “e”, remove the letter, look in the $wares array, find that 1 is the key, and add 63, and get 64 for excellent iron, and add it to the string.

    So I will not be needing to bring back data based on items in a string, I just bring back data in the string, so I can use a foreach to loop through the string brought back from the DB and put into an array, and spit out the goods wanted through that system.

    I did not know that the function didn’t know where $wares was, so maybe that’ll solve the problem. serialize and unserialize just might work…I wasn’t ware of these either.

    # November 16, 2012 at 2:11 pm

    Okay now I’ve changed to serialize and unserialize. The page _is_ “loading”. It’s complaining my SQL syntax isn’t valid though, which I can’t figure out why.

    UPDATE profile SET selling=$sell, buying=$buy, motto=$motto WHERE id=1

    $sell and $buy are the results of serializing the arrays, and $motto is a string.

    # November 16, 2012 at 9:34 pm

    Hi there – looks like based on what you’re trying to do you may benefit from using 2 more tables in your database. Specifically – you could build these tables:

    **ware** & **profileware**

    **ware** should have an ID and a VARCHAR field for the name of the ware

    **profileware** should have an ID and a wareID and a profileID and a TINYINT called _isbuying_ that is 1 for buying and 0 for selling (or equivalent)

    **ware** will keep track of all of the wares available, should just be the 126 listed out. and **profileware** will keep track of the relationship between the profile (user) and the ware. so if my profileID is 5 and i want to buy iron (wareID: 1) and sell sheep (wareID: 4) there should be two rows in profileware for me:

    ID: 1, profileID: 5, wareID: 1, isbuying: 1
    ID: 2, profileID: 5, wareID: 4, isbuying: 0

    then in your HTML markup – name each of the wares something like this:

    The value corresponds to the ID of the ware, and ALL of the checkboxes can have the same name “buyware[]“

    When the user saves the data, you will have an array of all of the wares they have selected. In the DB erase all of the profileID records from profileware and insert new records for each of the wares they have selected by doing a foreach on $_POST – also be sure to keep track of whether they are buying or selling so buying checkboxes are called name=”buyware[]” and selling are name=”sellware[]” – etc.

    Is this making sense? Then read into MySQL JOINs and reap the rewards of relational databases! :)

    # November 16, 2012 at 9:57 pm

    Am I understanding correctly that `$sell` and `$buy` are the values returned by `serialize()`?

    `serialize()` returns a string, which needs to be delimited by single quotes in a MySQL query. The string may also include characters (e.g., ` ‘ `) that need to be escaped before being used in your query.

    < ?php
    $str = serialize( $array );
    # assuming $DB is an instance of mysqli
    $x_str = $DB->real_escape_string( $str );
    $query = “UPDATE `profile` SET `col`=’$xstr’ …”;

    Honestly, though, you could be doing this in a much less complicated way.

    .1. define *all* key=>ware pairs (including “excellent” wares):

    $wares = array(
    1 => ‘iron’
    ,2 => ‘oranges’
    // . . .
    ,64 => ‘excellent iron’
    ,65 => ‘excellent oranges’
    // . . .
    );

    .2. in your form, use the keys as the values in the first place:

    < .form>


    If you’re not already doing so, you can use PHP to generate this form (which would be easier, and much less error-prone, than writing it by hand):

    < ?php
    # loop through $wares array and create HTML inputs
    foreach( $wares as $key => $ware ){
    $checkbox[] = ‘ ‘. $ware;
    }

    .3. now, when your user submits the form, you have a pre-made array containing the keys of the items they’ve checked, which you can serialize directly:

    < ?php
    $sellStr = serialize( $_POST );
    $x_sellStr = $DB->real_escape_string( $sellStr );
    $query = “UPDATE `profile` SET `selling`=’$x_sellStr’ . . .”;

    Simpler, quicker, less error-prone.

    ********************
    ### Edit

    I missed @thatericsmith ‘s reply.

    What he’s describing is the same thing I was talking about in my first reply – *normalization*. It allows the database to “understand” the values you’re storing, rather than storing a big ugly string that has to be given back to PHP before it can be searched.

    # November 21, 2012 at 1:31 pm

    Hum thanks, though due to the way I must display all the different wares, excellent and not, your method won’t quite work.

    Turns out, my knowledge of string manipulation functions isn’t that wide. I ended up not using that long array at all…I just used implode and explode since the CSS that styled the wares was in the written out names of the wares.

    Well all’s well that ends well :) Thanks traq for all your help :)

Viewing 14 posts - 1 through 14 (of 14 total)

You must be logged in to reply to this topic.

*May or may not contain any actual "CSS" or "Tricks".