Customize Jetpack Sharing Buttons

Want to cus­tomize Jet­pack and the shar­ing but­tons it offers? By adding a sim­ple fil­ter to functions.php or inc/jetpack.php if your theme is based on _s, you can actu­ally avoid the Sharedaddy stylesheet from being enqueued.

/**
* Remove Jetpack's sharing script.
*/
function _s_remove_sharedaddy_script() {
remove_action( 'wp_head', 'sharing_add_header', 1 );
}
add_action( 'template_redirect', '_s_remove_sharedaddy_script' );

Now you can add you own cus­tom CSS with­out wor­ry­ing about mul­ti­ple lev­els like .site-main .entry-content > .sharedaddy .sd-title, or hav­ing to use !impor­tant to over­write the Sharedaddy stylesheet.

If you want to go a bit fur­ther, you can use some jQuery/Javascript. For exam­ple, if you want to cre­ate a link that, when you click on it, tog­gles the shar­ing buttons:

1) Add some CSS to hide the div:
.sd-sharing-enabled:not(#jp-post-flair) {
display: none;
}

2) Then cre­ate some (very basic) jQuery to do the magic:

/*
* Create a toggle button for sharedaddy.
*/
function sharedaddy_toggle() {

// Cre­ate tog­gle but­ton
$( ‘.sd-sharing-enabled:not(#jp-post-flair)’ ).each( func­tion() {
$( this ).before( ‘’ );
} );

// Click to open
$( ‘.entry-content’ ).on( ‘click’, ‘.sharedaddy-sharing’, func­tion() {
$( this ).next( ‘.sd-sharing-enabled’ ).tog­gle();
} );

}

Make sure to load the func­tion after the window’s loaded, and after a post-load (for Infi­nite Scroll).

To do the same with the Related Posts mod­ule or Likes mod­ule like so:

/**
* Remove Jetpack's related-posts and likes scripts.
*/
function _s_remove_jetpack_scripts() {
wp_dequeue_style( 'jetpack_related-posts' );
wp_dequeue_style( 'jetpack_likes' );
}
add_action( 'wp_enqueue_scripts', '_s_remove_jetpack_scripts' );

Note: The Likes mod­ule isn’t fully cus­tomiz­able because the but­tons are located in an iframe.

Building a Web App with Symfony 2: Finalizing

This entry is part 3 of 3 in the series Build­ing a Per­sonal Web App Head To Toe With Sym­fony 2

In Part 1 and Part 2 of this series, I have cov­ered the basics of using Sym­fony 2 to develop a func­tion­ing web site.

In this part of the tuto­r­ial, I will cover some more advanced tech­niques and fin­ish the project with pag­i­na­tion, image water­marks and NativeQuery.

The code we’ll be using is iden­ti­cal to the code from Part 2 – the fea­tures are already there, they just weren’t discussed.

Image water­marks

See­ing as there’s already plenty of image manip­u­la­tion and water­mark­ing through Imag­ick tuto­ri­als avail­able on Site­Point, and owing to the fact that we don’t do any advanced image manip­u­la­tion in this par­tic­u­lar project, we’ll stick to PHP’s default image main­pu­la­tion library – GD.

In gen­eral, when there is “image pro­cess­ing”, we are talk­ing about an action or actions applied to an image before we even­tu­ally show it using the <img> tag. In my appli­ca­tion, this is done in two steps:

  • Cre­ate a route to cap­ture the “image dis­play request” and map it to an action in a controller.
  • Imple­ment the pro­cess­ing in the action.

Route con­fig­u­ra­tion

The route for dis­play­ing an image after pro­cess­ing is simple:

    cover: 
        pattern: /books/cover/{id}_{title}_{author}_{width}.png
        defaults: {_controller: trrsywxBundle:Default:cover, width: 300}

In a tem­plate, we can invoke the call to dis­play the processed image by:

    <img src="{{path("cover", {'id':book.id, 'author':author, 'title':book.title}) }}" alt="{{book.title}}'s cover" title="{{book.title}}'s cover"/>

So every time this <img> tag is encoun­tered, a processed image will be displayed.

Image pro­cess­ing

In this appli­ca­tion, we do two things before dis­play­ing the image:

  1. Depend­ing on whether or not a book cover image exists, dis­play it, or dis­play the default cover image;
  2. Add a water­mark and adjust the size (300px wide in book detail view and 200px wide in read­ing list view).

The com­plete code is in src/tr/rsywxBundle/Controller/DefaultController.php in the func­tion coverAction. The code is sim­ple and straight­for­ward and I’ll just show you the out­put in Detail View for both a real book cover and a default cover:

Note that I have cre­ated a “cover” folder under “web” to hold the default cover and the scanned book cov­ers. I also used a Chi­nese TTF to dis­play the water­mark texts. Please feel free to use your own font (and copy that font to the “cover” folder).

On a higher-traffic site, the cor­rect course of action would be to cache the auto­gen­er­ated images much like Lukas White did in his arti­cle, but I’ll leave that up to you to play around with.

Pag­i­na­tion

There are also a lot of arti­cles on pag­i­nat­ing a big dataset. In this tuto­r­ial, I will show you how I did it in this app, and we’ll test it.

The source code for the class is in src/tr/rsywxBundle/Utility/Paginator.php.

The code itself is easy to read and does not involve any­thing par­tic­u­larly advanced, so I will just dis­cuss the process.

There are two fun­da­men­tal val­ues in a Pag­i­na­tion class:

  1. How many records in total and how many pages in total?
  2. What is the cur­rent page and how to con­struct an eas­ily acces­si­ble page list for fur­ther processing ?

Many pag­i­na­tion classes often deal with data retrieval too, but this is not good prac­tice: pag­i­na­tion should only deal with things related to pag­i­na­tion, not the data itself. The data is the domain of the Entity/Repository.

If we go back to the imple­men­ta­tion of get­ting the books match­ing cer­tain cri­te­ria, you will notice how the two steps (get data and do pag­i­na­tion) are sep­a­rated in the controller:

File location: src/tr/rsywxBundle/Controller/BookController.php

    public function listAction($page, $key)
    {
        $em = $this->getDoctrine()->getManager();
        $rpp = $this->container->getParameter('books_per_page');

        $repo = $em->getRepository('trrsywxBundle:BookBook');

        list($res, $totalcount) = $repo->getResultAndCount($page, $rpp, $key);
        //Above to retrieve data and counts
        //Below to instantiate the paginator

        $paginator = new \tr\rsywxBundle\Utility\Paginator($page, $totalcount, $rpp);
        $pagelist = $paginator->getPagesList();

        return $this->render('trrsywxBundle:Books:List.html.twig', array('res' => $res, 'paginator' => $pagelist, 'cur' => $page, 'total' => $paginator->getTotalPages(), 'key'=>$key));
    }

The con­struc­tor of my pag­i­na­tor takes 3 parameters:

  • page: to tell what is the cur­rent page. This will be used to return a list for pages to show as click­able links in the template;
  • total­count: to tell the count of the results. This will be used to cal­cu­late the total pages together with the rpp parameter;
  • rpp: short for records per page.

In my cur­rent imple­men­ta­tion, I used a sim­ple ver­sion of pag­i­na­tion show­ing only “First”, “Pre­vi­ous”, “Next”, and “Last” page links, but you can try out dif­fer­ent types by using the getPagesList function.

Take for exam­ple a page list like this:

    1 2 3 4 5

The key here is in the getPagesList func­tion which makes sure that the cur­rent page is always in the mid­dle, or if there aren’t enough pages, it makes sure it’s in the cor­rect position.

    public function getPagesList()
    {
        $pageCount = 5;
        if ($this->totalPages <= $pageCount) //Less than total 5 pages
            return array(1, 2, 3, 4, 5);

        if($this->page <=3)
            return array(1,2,3,4,5);

        $i = $pageCount;
        $r=array();
        $half = floor($pageCount / 2);
        if ($this->page + $half > $this->totalPages) // Close to end
        {
            while ($i >= 1)
            {
                $r[] = $this->totalPages - $i + 1;
                $i--;
            }
            return $r;
        } else
        {
            while ($i >= 1)
            {
                $r[] = $this->page - $i + $half + 1;
                $i--;
            }
            return $r;
        }
    }

To make sure this func­tion really works, we’ll have to test it before using it. We’ll use PHPUnit as the test bench. Please refer to the offi­cial site for detailed instruc­tions on how to install it. I used the phpunit.phar way to down­load the pack­age and place it in my project root folder.

To test the Pag­i­na­tor class we just cre­ated, firstly we need to cre­ate a folder Utility under src/tr/rsywxBundle/Tests. All tests in Sym­fony should go under src/tr/rsywxBundle/Tests. In the Utility folder, cre­ate a PHP file named PaginatorTest.php:

    namespace tr\rsywxBundle\Tests\Utility;

    use tr\rsywxBundle\Utility\Paginator;

    class PaginatorTest extends \PHPUnit_Framework_TestCase
    {
        public function testgetPageList()
        {
            $paginator=new Paginator(2, 101, 10);
            $pages=$paginator->getTotalPages();
            $this->assertEquals($pages, 11);
            $list=$paginator->getPagesList();
            $this->assertEquals($list, array(1,2,3,4,5));

            $paginator=new Paginator(7, 101, 10);
            $list=$paginator->getPagesList();
            $this->assertEquals($list, array(5,6,7,8,9));

            $paginator=new Paginator(10, 101, 10);
            $list=$paginator->getPagesList();
            $this->assertEquals($list, array(7,8,9,10,11));
        }
    }

This kind of test is called a Unit Test. It tests a par­tic­u­lar unit of the program.

In testgetPageList func­tion, we basi­cally instan­ti­ate the object we want to test (a pag­i­na­tor) with vir­tu­ally any com­bi­na­tion of para­me­ters we can think of. We then call some meth­ods of that object and test the valid­ity of the result by using asser­tions. Here we only use the method assertEquals.

In the exam­ple $this->assertEquals($list, array(7,8,9,10,11)) from the $paginator object we cre­ated, we know there should be a total of 11 pages (with 101 records in total and 10 records per page), and page 10 as the cur­rent page will return a page list 7,8,9,10,11 as page 10 is very close to the end. We assert this and if that asser­tion fails, there must be some­thing wrong in the func­tion logic.

In our com­mand line/terminal, we run the fol­low­ing command:

php phpunit.phar -c app/

This reads the con­fig­u­ra­tion file for PHPUnit from the app/ folder (phpunit.xml.dist is gen­er­ated by the Sym­fony instal­la­tion. DON’T CHANGE IT!)

Note: Please delete all other test files auto-generated by Sym­fony (like Controller folder under Tests). Oth­er­wise, you will see at least one error.

The above com­mand will parse all test files under Tests and make sure all asser­tions pass. In the above exam­ple, you will see a prompt say­ing some­thing like OK, 1 test, 4 assertions. This means all the tests we cre­ated have passed and thus proved the func­tion behaves prop­erly. If not, there must be some­thing wrong in the code (in the imple­men­ta­tion or in the test).

Feel free to expand the test file for the Pag­i­na­tor class.

It is always a good prac­tice to test a home-made mod­ule before it is used in your program.

For a more in-depth look at PHPUnit and test­ing in PHP, see any of SitePoint’s numer­ous PHPUnit arti­cles.

Native­Query

Our data­base has a table called book_visit, we use time­stamp as the data type to log the time of a visit to the book detail page. We need to do some sta­tis­tics aggre­ga­tion on the vis­its and one of them is to get the total visit count by day (my “day” is in the +8 hours timezone).

In SQL, this is easy:

    select count(v.bid) vc, date(from_unixtime(v.visitwhen+15*60*60)) vd from book_visit v group by vd order by vd

In the above, 15*60*60 is there to adjust my server time to my timezone.

How­ever, if you try to use sim­i­lar gram­mar in Symonfy (chang­ing the table name to its FQN, of course), an error prompt will tell you some­thing like date function is not supported. To solve this, one way is to use pure SQL:

    $q = $em->getConnection()->prepare('select count(v.bid) vc, date(from_unixtime(v.visitwhen+8*60*60)) vd from book_visit v group by vd order by vd');
    $q->execute();
    return $q->fetchAll();

Or as rec­om­mended by Sym­fony and Doc­trine, we can (and should) use createNativeQuery and ResultSetMapping.

    public function getVisitCountByDay()
    {
        $em = $this->getEntityManager();

        $rsm=new \Doctrine\ORM\Query\ResultSetMapping;

        $rsm->addScalarResult('vc', 'vc');
        $rsm->addScalarResult('vd', 'vd');

        $q=$em->createNativeQuery('select count(v.bid) vc, date(from_unixtime(v.visitwhen+15*60*60)) vd from book_visit v group by vd order by vd', $rsm);

        $res=$q->getResult();

        return $res;

    }

In the exam­ple above, the most crit­i­cal state­ments are to cre­ate a Result­SetMap­ping and add results to that mapping.

vc (visit count) and vd (visit date) both appeared twice in the addScalarResult call. The first is a col­umn name that will be returned from the query and the sec­ond is an alias for that col­umn. To pre­vent the com­pli­ca­tion of cre­at­ing more names, we just use the same names.

A scalar result describes the map­ping of a sin­gle col­umn in an SQL result set to a scalar value in the Doc­trine result. Scalar results are typ­i­cally used for aggre­gate val­ues but any col­umn in the SQL result set can be mapped as a scalar value.

The above func­tion­al­ity is not imple­mented in the final code. Take it as home work.

Con­clu­sion

This is far from a com­plete tuto­r­ial for Sym­fony. There’s plenty not cov­ered (forms, secu­rity, func­tional test­ing, i18n, etc), which could eas­ily take another 10–12 parts. I highly rec­om­mend you read the full offi­cial doc­u­men­ta­tion pro­vided by Sym­fony, which can be down­loaded here.

This being my first time writ­ing a series in PHP and for Site­point, I would appre­ci­ate any con­struc­tive crit­i­cism and gen­eral feed­back you could throw my way.

The post Build­ing a Web App with Sym­fony 2: Final­iz­ing appeared first on Site­Point.

What’s New in WordPress 3.7

I like the fre­quency of Word­Press updates. They’re gen­er­ally released every few months so you receive some great new fea­tures and bug fixes. But they’re not so fre­quent that you’re updat­ing all your sites every other day.

Word­Press 3.7 was released on Octo­ber 24, 2013. You can down­load the files from word​press​.org/​d​o​w​n​l​o​ad/ or you can fol­low the Updates links from within the Word­Press con­trol pan­els. The Word­Press team state “you might not notice a thing, and we’re okay with that”. Per­haps the only thing you will notice is Word­Press requires less main­te­nance than ever…

Auto­mated Back­ground Updates

I’ve never encoun­tered any issues with the one-click upgrade — it just works. Word­Press 3.7 decre­ments it to a zero-click upgrade process! From now on, main­te­nance and secu­rity updates are applied in the back­ground. You should only see an “Upgrade Now” but­ton when ver­sion 3.8 is released.

This fea­ture may not appeal to the more cau­tious admin­is­tra­tors among you, but the Word­Press team tested 110,000 sites with­out a sin­gle fail­ure. On aver­age, updates take less than 25 sec­onds and will only place Word­Press in main­te­nance mode for a few seconds.

For­tu­nately, it’s pos­si­ble to con­fig­ure and dis­able back­ground upgrades. Look out for a tuto­r­ial on Site­Point soon.

Updated Pass­word Strength Meter

The new pass­word strength meter now rec­og­nizes com­mon weak pass­word pat­terns such as names, dates, key­board sequences, num­ber sequences and even pop-culture ref­er­ences. It’s slightly scary — some of my pass­words which were pre­vi­ously high­lighted as “strong” have been re-classified as “very weak”!

Improved Search

Word­Press’ search facil­i­ties had been ade­quate but rarely resulted in Google/Bing-like accu­racy. You can make your own improve­ments but it puts an onus on the user to apply rel­e­vant filters.

Word­Press 3.7 improves search with rel­e­vancy order­ing — rather than just by date which tended to pri­or­i­tize blog posts above pages. For exam­ple, a search term which matches a title should appear toward the top of the list. It’s a lit­tle dif­fi­cult to eval­u­ate the improve­ments unless you have 3.6 and 3.7 instal­la­tions with iden­ti­cal con­tent, but the few basic tests I tried seemed better.

Improved Global Support

The Word­Press team has improved local­iza­tion and promise to pro­vide faster and more com­plete trans­la­tions. Lan­guage files will also be kept up-to-date using the auto­matic back­ground upgrades. It’s a sen­si­ble move: Word­Press pow­ers around a fifth of all web­sites and a large num­ber of those won’t be using English.

Date Queries

Devel­op­ers can now query posts within a cer­tain date range or match cer­tain cri­te­ria, such as those arti­cles posted on a Fri­day dur­ing Jan­u­ary this year. For more infor­ma­tion, refer to the Word­Press codex.

Multi-site wp_get_sites() Function

The new wp_get_sites() func­tion allows you to fetch an array of all sites on your Word­Press multi-site net­work with­out need­ing to use direct data­base queries. It won’t be use­ful to every­one and there’s no doc­u­men­ta­tion yet, but it’s there should you need it.

Per­son­ally, I’m begin­ning to won­der whether all Word­Press instal­la­tions should be multi-site by default? The team pos­si­bly needs to make the inter­face a lit­tle eas­ier and address domain map­ping, but I’d cer­tainly appre­ci­ate it!

Mis­cel­la­neous Updates

If that’s not enough…

  • acces­si­bil­ity improve­ments have been made
  • codex and in-system doc­u­men­ta­tion has been updated
  • more than 437 bugs have been closed by the 211 developers

Word­Press 3.7 is a great update. There haven’t been fun­da­men­tal changes to the core, so I sus­pect most plu­g­ins and themes will be com­pat­i­ble. Unless you know otherwise?

All going well, Word­Press 3.8 will be released at the end of 2013. We may see a new dash­board, themes page and search facilities.

The post What’s New in Word­Press 3.7 appeared first on Site­Point.

Wizpert – incentivized helping

On Octo­ber 18th 2013, I got an email invit­ing me to a new plat­form, Wiz­pert. Even though the ser­vice mis­tak­enly iden­ti­fied me as the owner of Google’s PHP-for-GAE blog, I tested it out briefly, and formed a hasty opin­ion.

Not half an hour later, their CEO, Michael Wein­berg got in touch with me, want­ing to clar­ify some mis­con­cep­tions I listed. This was a big plus in my book – proper PR con­trol of such rapid­ity is of extreme importance.

We arranged a Skype call for the fol­low­ing Mon­day, and after a brief chat cov­ered all the aspects that con­cerned me and more.

What is Wizpert?

Wiz­pert is a plat­form on which experts in cer­tain areas can get reg­is­tered as “Wiz­perts”. Vis­i­tors then have the oppor­tu­nity to chat them up with ques­tions they might be hav­ing about any topic cur­rently avail­able – from rela­tion­ship advice to programming.

If the Wiz­pert was help­ful, the vis­i­tor can opt to reward them with coins, and a cer­tain amount of coins can be exchanged for real money. The more you accu­mu­late and exchange at once, the bet­ter the exchange ratio.

Vis­i­tors can pur­chase these coins for real money, and of course, the more they pur­chase in one go, the bet­ter the money-to-coins ratio.

Essen­tially, it’s a paid helpdesk. Imag­ine hav­ing one-on-ones on Stack​Over​flow​.com and (some­times) being paid for it.

Tech­ni­cally, Wiz­pert is very well done. Being very young, they cer­tainly do have some bugs to iron out, but their inte­gra­tion with Google Hang­outs and Skype is flaw­less. You con­nect those ser­vices with your Wiz­pert account, and every time some­one would like to chat with you, you’ll get pinged on any you’re avail­able on. One could argue that this approach pro­duces too much clut­ter in Skype (see Fig 1), but it’s really no big deal.

What’s the earn­ing potential?

Not great. When vis­i­tors first sign up, they get 100 pro­mo­tional coins. You can get those coins through var­i­ous means – even just vis­it­ing the site dur­ing the launch period. How­ever, pro­mo­tional coins can­not be exchanged for money. They can be used to extend a chat’s dura­tion (every chat has a 3 minute intro period after which it has to be extended by either the Wiz­pert or the vis­i­tor), to talk to other experts, etc. To reward some­one, a vis­i­tor must pur­chase coins – only pur­chased coins can be exchanged for money.

“So what are the ratios?”, you might be think­ing. In my ini­tial post, I missed one con­ver­sion rate and made a mis­cal­cu­la­tion. If, while pur­chas­ing coins, you go to the check­out page, another option appears – 10k coins for $200. See­ing as 30k coins can be exchanged for $500, this makes for the platform’s mar­gin of $100 (if both the Wiz­pert and vis­i­tor exchange only at the best ratio) which is, admit­tedly, rather fair. Right, but all this still means peo­ple need to buy coins to reward those they deem extra help­ful and no one really does that. Or do they?

Michael men­tioned in our chat that, as a mat­ter of fact, they’re not only see­ing a high sat­is­fac­tion of vis­i­tors as far as the chats go, but also a very high per­cent­age of peo­ple actu­ally going the extra mile, buy­ing coins and reward­ing peo­ple. I myself have been given coins as well, so my ini­tial prej­u­dice seems to have been very wrong.

Now, granted, this still doesn’t come down to a lot of money. Even if you earned 1000 coins per day, that’s 30k per month, which is $500, other fees notwith­stand­ing. Not bad as pocket money, espe­cially if you spend the day doing open source and help­ing peo­ple any­way, but not worth quit­ting your job over either. There’s some­thing else to be earned, how­ever, and we’ll get to that in a bit.

As a dev Wiz­pert, what exactly do I do there?

Let’s take a look at some exam­ple ques­tions (paraphrased):

Q1: “[…]Get this error on line 75 Fatal error: Call to a mem­ber func­tion setTimezone() on a non-object”

    <div class="pending Incidents">
        <table id="upcoming" width="100%" border="1">
  <tr>
    <th width="20%" >Available Units</th>
    <th width="10%" >Recommended Station</th>
    <th width="20%" >Incident Type</th>
    <th width="40%" >Address/Location</th>
    <th width="5%" >P/U Time</th>
    <th width="5%" >Apt Time</th>

  </tr>
<?php while ($fetchselupcoming = mysql_fetch_assoc($resultupcoming)) { ?>
  <tr>
<?php
  $pickup = $fetchselupcoming['pu'];
  $apttime = date('H:i', strtotime($fetchselupcoming['at']));
    echo 
        "<td>";
        echo "<form name=\"dispatch\" method=\"post\" action=\"dispatch.php\">". 
        "<select name=\"unit\">".$option."</select>".
        "<input type=\"hidden\" name=\"status\" value=\"3\">".
        "<button type=\"button\">Dispatch</button>". 
        "</form>".
        "</td>".
        "<td>".$fetchselupcoming['station']."</td>".
        "<td>".$fetchselupcoming['name']."</td>".
        "<td>".$fetchselupcoming['full_address_2']."</td>".
        "<td>"
        .$dt= new DateTime($pickup, new DateTimeZone('EST')).
        $dt->setTimezone(new DateTimeZone('America/Detroit')).
        $dt->format('H:i').

        "</td>".
        "<td>"
        .
        "</td>";

?>
        </tr>
<?php };?>
          </table>

</div>

Any inter­me­di­ate and above PHP devel­oper will real­ize this code is utter hor­ror. Obvi­ously, the per­son is try­ing to echo some data­base fetched val­ues into a table, but the code is fail­ing. Due to the chaotic nature of the code’s lay­out, it’s hard to pin­point the error at first glance.

The first thing we do is, thus, past­ing the code into a high qual­ity IDE such as PHP­Storm. Next, we run the aut­o­for­mat­ter to repair the lay­out, so we can scan through the code in a more fluid man­ner. We get this:

Aside from the invalid width attrib­utes and an unde­fined vari­able the client must have left behind in an included file or out­side the scope of pasted code, we see only one other part flar­ing up – the Date­Time sec­tion on the lines where the error hap­pens. Mou­s­ing over the sec­tion, an error is revealed clear as day: Method __toString is not implemented for \DateTime.

Now, while this might be very obvi­ous to most inter­me­di­ate and above devs, error hint­ing of this type enables even begin­ners to debug other people’s code, while improv­ing their own error spot­ting skills in the process.

Obvi­ously, the client is mak­ing a com­mon mis­take. Mix­ing views and logic this much is never a good idea, and echo­ing out strings of HTML almost always leads to bad code, espe­cially in bad code edi­tors which don’t high­light the issues. In this par­tic­u­lar case, the client is print­ing out an entire string of HTML, and sim­ply tacks on a series of chained Date­Time method calls into it.

The solu­tion is to sim­ply remove the instan­ti­a­tion and setTimezone from the string, and move it above every­thing. This doesn’t turn this into qual­ity code, but at least the code now works, the client is happy, and he can reward you with coins or even hire you for a more proper rewrite if you advise him to do so (for exam­ple, mysql_fetch_assoc should be dis­carded, the table should be printed in HTML, not PHP, it should be styled in CSS, not with attempted widths on table head­ings, etc).

Let’s look at another one.

Q2: Login system

As you can see, we hit a wall before even mov­ing. Obvi­ously, this per­son was a new­bie – per­haps even a first encounter with PHP. What fol­lowed was a patient 10 minute expla­na­tion of what data­base to use, the schema of the data­base, the login/register form, and the basics of how a login system’s logic works. I ended the chat with some use­ful links and explained how I can be con­tacted again, should he need help regard­ing this same issue in the future.

Chats are gen­er­ally 10–20 min­utes in length. Any­thing over, and I encour­age you as a devel­oper to men­tion the coin reward. After all, it is your time that’s being spent here. I don’t men­tion coins for their mon­e­tary value, how­ever; I men­tion them because they cement the rela­tion­ship, keep the client focused on this one chat and one prob­lem, and force both them and you to become more emo­tion­ally invested in the process, which brings us to the next section.

What Wiz­pert offers is worth more than money

A long time ago, I was a mem­ber of a PHP men­tor­ing effort. It’s a pro­gram that teams up a senior with a junior, Sith lord style. Hav­ing an appren­tice whom you can unload your triv­ial work onto for petty cash while teach­ing them proper cod­ing tech­niques in the process is a won­der­ful, albeit time con­sum­ing and some­times nerve-wracking expe­ri­ence. I remem­ber it made me bet­ter at com­mu­ni­cat­ing with peo­ple, at trans­lat­ing ideas from my head to a more com­mon lan­guage for every­one to under­stand, and it taught me (some) patience. But it also took up too much of my time – hav­ing a con­stant appren­tice is almost a full time (unpaid) job in itself. One of the first chats on Wiz­pert reminded me of that experience.

When you get a ran­dom per­son in a chat with you, and that per­son has a prob­lem, it’s often too easy to think of them as “stu­pid” for not try­ing out this or that solu­tion, for hav­ing weak Google-fu, or for sim­ply not being able to under­stand the very lan­guage they’re dab­bling in. After all, pro­gram­ming is noth­ing more than talk­ing to the com­puter in Eng­lish, so how hard can it be, right? Wrong. So very wrong.

The few chats I’ve had on Wiz­pert re-opened my eyes to this. I’ve encoun­tered prob­lems that were, at first glance, triv­ial to me. But as me and the client dug deeper, and the prob­lem kept get­ting more com­plex, I felt a drive, a hunger, a curios­ity. I wanted to solve it, I wanted to dig around more and find out about it. My ini­tial impulse was “Oh, yeah, that’s this and that and you gotta do that” fol­lowed by imme­di­ate thoughts of dis­missal, but even­tu­ally, it turned into “Have you tried this? Have you tried that?”. The cocky cer­tainty was dis­si­pat­ing. This wasn’t the last chat of this type – prob­lems I would deem triv­ial and banal any other day seemed inter­est­ing in almost every one, because they taught me much more than the solu­tion to a silly new­bie issue.

What I’m say­ing is: through solv­ing these obvi­ous and mostly unchal­leng­ing prob­lems and through review­ing my chat logs, I came to under­stand which parts of my approaches to clients and new­bies in gen­eral I need to improve. I learned to approach both them and their needs from a dif­fer­ent angle. I’m improv­ing my Eng­lish skills towards non-native speak­ers, learn­ing how to keep things sim­ple and under­stand­able, and I’m slowly mas­ter­ing the art of dig­ging through untold infor­ma­tion to get to the source of a problem.

Con­clu­sion

What Wiz­pert can offer is worth more than money – it’s per­sonal growth. Your patience, your knowl­edge, your speed, your com­pas­sion – every­thing is put to the test. If you’re at all inter­ested in upgrad­ing not only your cod­ing skills, but your peo­ple skills, your intu­ition and your pre­ci­sion in prob­lem diag­no­sis, I encour­age you to give Wiz­pert a go. You can find me there.

The post Wiz­pert – incen­tivized help­ing appeared first on Site­Point.

Selling Downloads with Stripe and Laravel

Dig­i­tal goods are an increas­ingly valu­able com­mod­ity. Whether you’re a designer sell­ing tem­plates or font files, a devel­oper charg­ing for pack­ages of code or a musi­cian sell­ing MP3s, sell­ing dig­i­tal goods online is often far eas­ier than phys­i­cal goods – with much lower pro­duc­tion costs and no deliv­ery charges.

In this arti­cle I’ll show how you can imple­ment a sim­ple store sell­ing dig­i­tal goods using PHP along with Stripe, a pay­ment provider who aims to make it eas­ier than ever to take online pay­ments since you don’t need to set up spe­cial mer­chant accounts or deal with com­plex pay­ment gateways.

Before you Begin

You’ll first need to set up an account with Stripe. Please note that the ser­vice is cur­rently only avail­able in the US, UK, Ire­land and Canada. You may wish to check the blog or fol­low them on Twit­ter to be kept up to date in regards to aval­a­bil­ity in other countries.

Set­ting up an account for test­ing takes no time at all, and doesn’t require any com­plex finan­cial ques­tion­naires or infor­ma­tion. You’ll need to take a note of your test API key and pub­lish­able key for later.

Set­ting Up

For this exam­ple appli­ca­tion I’m going to use Lar­avel. It’ll take care of some of the bread-and-butter stuff such as rout­ing, tem­plat­ing and ini­ti­at­ing the down­loads, but the exam­ple shouldn’t be too dif­fi­cult to adapt for other frame­works (or indeed, no frame­work at all). Note that you can clone the entire exam­ple from Github.

Get started by installing Lar­avel via Com­poser:

composer create-project laravel/laravel stripe-downloads --prefer-dist

Include the fol­low­ing in the require sec­tion of your composer.json file, and run composer update:

"abodeo/laravel-stripe": "dev-master"

This pro­vides a sim­ple wrap­per to the Stripe SDK, allow­ing it to be used from within Lar­avel with­out hav­ing to worry about require’ing the appro­pri­ate files.

Pub­lish the con­fig­u­ra­tion file using:

php artisan config:publish abodeo/laravel-stripe

Then enter your API key and pub­lish­able key in app/config/packages/abodeo/laravel-stripe/stripe.php

Finally add the pack­age to your list of ser­vice providers (app/config/app.php):

'Abodeo\LaravelStripe\LaravelStripeServiceProvider',

Set­ting up the Database

Con­fig­ure and cre­ate your data­base, then run the fol­low­ing to cre­ate a migration:

php artisan migrate:make create_downloads_table

Here’s the rel­e­vant sec­tion (of the up() func­tion), to cre­ate a table for the down­loads we’re going to sell:

Schema::create('downloads', function($table)
{
    $table->increments('id')->unsigned();        
    $table->string('name', 255);      
    $table->string('filepath', 255);      
    $table->integer('price');            
    $table->timestamps();
});    

Note that price is an inte­ger, because inter­nally we’re only going to deal with cents / pence. Filepath will refer to the loca­tion of the file rel­a­tive to the app/storage directory.

The cor­re­spond­ing model is very simple:

// app/models/Download.php
class Download extends Eloquent {
    protected $fillable = array('name', 'filepath', 'price');
}

Finally, let’s seed the data­base with some sam­ple downloads:

class DownloadsSeeder extends Seeder {

    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        $data = array(
            array(
                'name'            =>    'Sample download 1',
                'filepath'    =>    'downloads/one.zip',
                'price'            =>    500,
            ),
            array(
                'name'            =>    'Sample download 2',
                'filepath'    =>    'downloads/two.zip',
                'price'            =>    1000,
            ),
        );

        foreach ($data as $properties) {

            $download = new Download($properties);
            $download->save();            

        }
    }

}    

A Sim­ple Homepage

Let’s cre­ate a sim­ple home­page which allows peo­ple to select which down­load they’d like to purchase:

Route::get('/', function()
{
    $downloads = Download::get();    
    return View::make('index', array('downloads' => $downloads));
});

And the view:

// app/views/index.blade.php
<h1>Select your download:</h1>

<table class="table table-bordered">
@foreach ($downloads as $download)
    <tr>
        <td>{{ $download->name }}</td>
        <td>&pound;{{ round($download->price/100) }}</td>
        <td><a href="/buy/{{ $download->id }}" class="btn btn-primary">Buy</a></td>
    </tr>
@endforeach
</table>

Tak­ing Payment

Stripe pro­vides two meth­ods for tak­ing card details. The first is a sim­ple but­ton, gen­er­ated using Javascript which launches a pay­ment form in a popup like so:

image

The sec­ond and more com­plex method allows to cre­ate the form your­self. That’s the method I’m going to use in this exam­ple. Here’s the route:

Route::get('/buy/{id}', function($id)
{
    $download = Download::find($id);    
    return View::make('buy', array('download' => $download));
});

And the view:

// app/views/buy.blade.php
<form action="" method="POST" id="payment-form" role="form">

  <div class="payment-errors alert alert-danger" style="display:none;"></div>

  <input type="hidden" name="did" value="{{ $download->id }}" />

  <div class="form-group">
    <label>
      <span>Card Number</span>
      <input type="text" size="20" data-stripe="number" class="form-control input-lg" />
    </label>
  </div>

  <div class="form-group">
    <label>
      <span>CVC</span>
      <input type="text" size="4" data-stripe="cvc" class="form-control input-lg" />
    </label>
  </div>

  <div class="form-group">  
    <label>
      <span>Expires</span>      
    </label>
    <div class="row">
      <div class="col-lg-1 col-md-1 col-sm-2 col-xs-3">
        <input type="text" size="2" data-stripe="exp-month" class="input-lg" placeholder="MM" />
      </div>  
      <div class="col-lg-1 col-md-1 col-sm-2 col-xs-3">
        <input type="text" size="4" data-stripe="exp-year" class="input-lg" placeholder="YYYY" />
      </div>
    </div>
  </div>

    <div class="form-group">
      <button type="submit" class="btn btn-primary btn-lg">Submit Payment</button>
  </div>
</form>

The eagle-eyed among you will notice that the card-related inputs are miss­ing one cru­cial attribute – name. With­out this, no data can pos­si­bly be passed to our server when the form gets sub­mit­ted. How can this be?

Actu­ally, this is delib­er­ate. We don’t want any credit card data being sent to our application.

What we’re going to do is inter­cept the sub­mis­sion of this form using Javascript. The card infor­ma­tion will be extracted from the form – notice the data-stripe attrib­utes – and securely sent to the Stripe servers along with our pub­lish­able key. Stripe are then respon­si­ble for val­i­dat­ing those details and all being well, return to us a spe­cial token. Once we have received that token, we can inject it into the form and POST the results as nor­mal – minus the card details.

Back on the server, we can then use this token in con­junc­tion with our pri­vate (API) key to actu­ally charge the user’s card. Should that code get inter­cepted up to this point, it’s use­less with­out our pri­vate key so there’s very lit­tle a hacker could do with it.

We start by ini­tial­is­ing the Stripe Javascript:

Stripe.setPublishableKey('@stripeKey');

In the code above, @stripeKey is a spe­cial Blade exten­sion which out­puts the pub­lish­able key. If you’re not using the blade tem­plat­ing library, you may wish to do some­thing like this instead:

Stripe.setPublishableKey('<?php print Config::get('stripe.publishableKey') ?>');

Next up, here’s the sub­mit han­dler for our form:

$('#payment-form').submit(function(e) {
  var $form = $(this);

  $form.find('.payment-errors').hide();

  $form.find('button').prop('disabled', true);

  Stripe.createToken($form, stripeResponseHandler);

  return false;
});

The func­tion to han­dle the response from Stripe:

    function stripeResponseHandler(status, response) {
      var $form = $('#payment-form');

      if (response.error) {

        $form.find('.payment-errors').text(response.error.message).show();
        $form.find('button').prop('disabled', false);
      } else {

        var token = response.id;

        $form.append($('<input type="hidden" name="stripeToken" />').val(token));

        $form.get(0).submit();
      }
  };

Note how the token gets injected into the form by dynam­i­cally cre­at­ing a new hid­den form ele­ment with the name stripeToken. This is the only payment-related data that gets submitted.

Should you exam­ine the response from the Stripe server, you’ll notice that in addi­tion to the token – the id prop­erty – there is a card dic­tio­nary object. Obvi­ously this does not con­tain the card num­ber or CVC, but it does include the type – Visa, Mas­ter­card etc – and the last 4 dig­its of the card num­ber. This is use­ful for gen­er­at­ing invoices or receipts; it’s quite com­mon to include this infor­ma­tion to indi­cate to the cus­tomer what card they used to pay.

Let’s build the POST form handler:

    Route::post('/buy/{id}', function($id)
    {
        // Set the API key    
        Stripe::setApiKey(Config::get('laravel-stripe::stripe.api_key'));

        $download = Download::find($id);

        // Get the credit card details submitted by the form
        $token = Input::get('stripeToken');

        // Charge the card
        try {
            $charge = Stripe_Charge::create(array(
                "amount" => $download->price,
                "currency" => "gbp",
                "card" => $token,
                "description" => 'Order: ' . $download->name)
            );

            // If we get this far, we've charged the user successfully

        Session::put('purchased_download_id', $download->id);
        return Redirect::to('confirmed');

        } catch(Stripe_CardError $e) {
          // Payment failed
        return Redirect::to('buy/'.$id)->with('message', 'Your payment has failed.');        
        }
    }

Let’s go through this.

First we’re set­ting the API key for Stripe. When we han­dled the form client-side we were okay with expos­ing the pub­lish­able key, because the token is use­less with­out the pri­vate API key.

Next we get the down­load being pur­chased from its ID, so we can get the name (used in the trans­ac­tion ref­er­ence) and its price (in cents / pence etc).

The value of $token is what we got from Stripe in the Javascript above, which we then injected into the form.

Next we use Stripe_Charge::create to actu­ally charge the card. The $cur­rency set­ting isn’t required, but it will default to USD even if you set up an account out­side of the US.

If the pay­ment suc­ceeds, we put the ID of the pur­chased item in the ses­sion. We’ll use this to con­trol access in a moment.

If the pay­ment fails – usu­ally because the bank declined the trans­ac­tion – a Stripe_CardError excep­tion gets thrown.

You can test the pay­ment process using the dummy card num­ber 4242-4242-4242-4242, along with any three-digit CVC and any expiry date – pro­vided it’s in the future.

The con­fir­ma­tion route is simple:

Route::get('/confirmed', function()
{
    $download = Download::find(Session::get('purchased_download_id'));
    return View::make('confirmed', array('download' => $download));
});

The view, which allows the buyer to down­load their file by click­ing the down­load button:

// app/views/confirmed.blade.php
<h1>Your Order has been Confirmed</h1>

<p>You can now download your file using the button below:</p>

<p><a href="/download/{{ $download->id }}" class="btn btn-lg btn-primary">Download</a></p>

Deliv­er­ing the File

Finally, we need to imple­ment the down­load link. We don’t want to sim­ply link to a pub­lic file, since we’re charg­ing for access. Instead, we’ll take the file from the application’s stor­age direc­tory – which isn’t web acces­si­ble – and deliver if, and only if, the cur­rent user has suc­cess­fully paid for it.

Route::get('/download/{id}', function($id)
{
    $download = Download::find($id);        
    if ((Session::has('purchased_download_id') && (Session::get('purchased_download_id') == $id))) {
        Session::forget('purchased_download_id');
        return Response::download(storage_path().'/'.$download->filepath);    
    } else {
        App::abort(401, 'Access denied');
    }
});

This link can only be used once; in prac­tice you’d prob­a­bly want to make it pos­si­ble to down­load a file again at a later date, but I’ll leave you to come up with ways of doing that.

Sum­mary

In this arti­cle I’ve shown how sim­ple it is to take pay­ments using Stripe, with­out hav­ing to worry about mer­chant accounts, pay­ment gate­ways or stor­ing sen­si­tive card infor­ma­tion. We’ve imple­mented a work­ing, albeit sim­ple pur­chas­ing process for dig­i­tal down­loads. Hope­fully you’ll have seen enough to get started imple­ment­ing it in your projects.

The post Sell­ing Down­loads with Stripe and Lar­avel appeared first on Site­Point.

Building a Web App With Symfony 2: Development

This entry is part 2 of 3 in the series Build­ing a Per­sonal Web App Head To Toe With Sym­fony 2

In Part 1, I have shown you how to set up Sym­fony 2 and link up the data­base. We also cov­ered some fun­da­men­tal con­cepts of the frame­work. In this part, we will link things up by cre­at­ing routes, con­trollers, entities/repositories, and views to get the site up and running.

Routes

Our instance of Sym­fony uses the YAML for­mat to con­fig­ure the routes for the appli­ca­tion. A sam­ple sec­tion of this site’s routes is shown below:

File loca­tion: src/tr/rsywxBundle/Resources/config/routing.yml

    home:
      pattern:  /
      defaults: { _controller: trrsywxBundle:Default:index }

    contact:
      pattern: /contact
      defaults:
        _controller: FrameworkBundle:Template:template
        template: 'trrsywxBundle:Default:contact.html.twig'

    book_list:
      pattern: /books/list/{page}/{key}
      defaults: 
        page: 1
        key: null
        _controller: trrsywxBundle:Book:list

    books_search: 
      pattern: /books/search
      defaults: {_controller: trrsywxBundle:Book:search}
      requirements: 
        _method: POST        

    book_detail:
      pattern: /books/{id}.html
      defaults: { _controller: trrsywxBundle:Book:detail}

Every app needs an entry point. This is the “home” route. pattern defines the URI pat­tern the route should match. As this is the entry point, / is used. defaults:_controller defines the action the appli­ca­tion will take when this route is matched. Please note the FQN for­mat it used to map the route (and the pat­tern) for the action to take. In this case, it means when­ever we are enter­ing the site with just its domain, the index action in the Default con­troller under the name­space trrsywxBundle will be triggered.

There are other para­me­ters you can set in the pat­tern and in the defaults. For exam­ple, the book_list route has a pat­tern with 2 para­me­ters in the URI: page means the cur­rent page when there is more than one page for the result to be dis­played (I will cover the Pag­i­na­tion in Part 3) and key is the key­word used to search books match­ing that key (in my cur­rent imple­men­ta­tion, I only search the begin­ning of the title of a book). All para­me­ters in the pattern must be within a pair of curly braces.

In book_list:default, I give the default val­ues for the above two para­me­ters: 1 for page and null for key. By doing so, a sim­ple URI like http://localhost/app_dev.php/books/list will list the 1st page of all books, while http://localhost/app_dev.php/books/list/3/Beauty will sim­ply list the 3rd page of all books whose title starts with Beauty (like “Beauty and Beast”).

You will also notice that the books_search route has requirements:_method set to POST. This restricts the call­ing method for that pat­tern to be just POST (in a form sub­mis­sion) as I don’t want the users to sim­ply visit /books/search in the browser. In my imple­men­ta­tion, this route is meant for inter­nal usage and should redi­rect to another page with the search result match­ing the cri­te­ria sub­mit­ted (POSTed)via a form.

The full doc­u­men­ta­tion on routes can be found on Symfony’s site.

Con­trollers

The next step is to define con­trollers. I have a total of 4 con­trollers located in src/tr/rsywxBundle/Controller. Namely, they are: BookController.php, DefaultController.php, LakersController.php, and ReadingController.php. I group the func­tions related to var­i­ous routes based on their functionality.

I will show just two con­trollers here, match­ing book_list and books_search.

    <?php

    class BookController extends Controller
    {
        // ... Many other functions here, see source

        public function listAction($page, $key)
        {
            $em = $this->getDoctrine()->getManager(); // Get the Entity Manager
            $rpp = $this->container->getParameter('books_per_page'); // Get the global parameter for how many books to show on one page

            $repo = $em->getRepository('trrsywxBundle:BookBook'); // Get the repository

            list($res, $totalcount) = $repo->getResultAndCount($page, $rpp, $key); // Get the result

            $paginator = new \tr\rsywxBundle\Utility\Paginator($page, $totalcount, $rpp); // Init the paginator
            $pagelist = $paginator->getPagesList(); // Get the pagelist used for navigation 

            return $this->render('trrsywxBundle:Books:List.html.twig', array('res' => $res, 'paginator' => $pagelist, 'cur' => $page, 'total' => $paginator->getTotalPages(), 'key'=>$key)); // Render the template using necessary parameters
        }

        public function searchAction(Request $req)
        {
            $q = $req->request->all(); // Get the posted data

            $page = 1; // Get which page to display 
            $key = $q['key']; // Get the search criteria

            $em = $this->getDoctrine()->getManager();
            $rpp = $this->container->getParameter('books_per_page');

            $repo = $em->getRepository('trrsywxBundle:BookBook');

            list($res, $totalcount) = $repo->getResultAndCount($page, $rpp, $key);

            $paginator = new \tr\rsywxBundle\Utility\Paginator($page, $totalcount, $rpp);
            $pagelist = $paginator->getPagesList();

            return $this->render('trrsywxBundle:Books:List.html.twig', array('res' => $res, 'paginator' => $pagelist, 'cur' => $page, 'total' => $paginator->getTotalPages(), 'key' => $key));
        }
    }

In a typ­i­cal con­troller fash­ion, it does three things:

  • Get all the prepa­ra­tion work done (input para­me­ters, get the Entity Man­ager, Repos­i­tory, etc);
  • Get the results from a repository;
  • Dis­play the results (with or with­out fur­ther pro­cess­ing) by ren­der­ing a tem­plate (Sym­fony uses Twig as its tem­plate engine).

Observe three things carefully:

  1. Look at how the para­me­ters we defined in route book_list (page and key) are passed into the func­tion call by name. Sym­fony does not care about the order of the para­me­ters’ appear­ance but requires a strict name match.

  2. Look at how the POSTed para­me­ters in a form are passed into searchAction and how we retrieve the nec­es­sary infor­ma­tion from the sub­mit­ted data.

  3. getParameter is a func­tion to retrieve global para­me­ters. The global para­me­ters are defined in the file app/config/parameters.yml.dist (auto­gen­er­ated with com­poser into .yml) and look like this:

    books_per_page: 10

Nor­mally, it is good prac­tice to leave the appli­ca­tion logic in the con­troller func­tions and the data provider in a repos­i­tory. This helps orga­nize the code and keep it re-usable.

A detailed doc­u­ment on Con­trollers can be found here.

Enti­ties and Repositories

In ORM’s method­l­ogy, an entity is the objec­tive reflec­tion of a data­base table. Instead by issu­ing native SQL com­mands in your PHP to manip­u­late the data, we can use intu­itive and straight­for­ward ways to CRUD the data. While the enti­ties gen­er­ated by Sym­fony con­tain sim­ple meth­ods to retrieve a data by ID, in a proper appli­ca­tion that is far from enough. Repos­i­to­ries are there to pro­vide more cus­tomized ways to manip­u­late data.

Enti­ties are gen­er­ated via a console/terminal com­mand: php app\console doctrine:generate:entity (See Part 1 or the offi­cial doc­u­men­ta­tion.) The gen­er­ated PHP entity files are located at src/tr/rsywxBundle/Entity. Take a look at those PHP files to under­stand more on how the data­base tables are mapped (via ORM) into a PHP class.

Note: Don’t make any changes to these PHP files directly. They are meant to be gen­er­ated by Symfony.

To cre­ate a repos­i­tory to hold all the cus­tomized data­base manip­u­la­tion meth­ods, you need to do two things:

  • Mod­ify cor­re­spond­ing ORM map­ping files (located at src/tr/rsywxBundle/Resources/config/doctrine) to spec­ify a repos­i­tory class for that data­base object;
  • Cre­ate all nec­es­sary func­tions to pro­vide required data­base manip­u­la­tion capa­bil­i­ties (like retriev­ing data).

Take my books col­lec­tion table (and its entity for example):

File loca­tion: src/tr/rsywxBundle/Resources/config/doctrine/BookBook.orm

    tr\rsywxBundle\Entity\BookBook:
        type: entity
        repositoryClass: tr\rsywxBundle\Entity\BookRepository # Add this line to indicate that we will use BookRepository.php as the repository class for BookBook table
        table: book_book
        fields:
    ...

After that, run php app\console doctrine:generate:entity again. You will notice a new BookRepository.php file is cre­ated under src/tr/rsywxBundle/Entity. You can now open that file and cre­ate your own func­tions for data manipulation:

        public function getResultAndCount($page, $rpp, $key=null)
        {
            // Get the book count
            $em = $this->getEntityManager();
            if ($key == 'null')
            {
                $q1 = $em->createQuery('select count(b.id) bc from trrsywxBundle:BookBook b');
            }
            else
            {
                $qstr = sprintf("select count(b.id) bc from trrsywxBundle:BookBook b where b.title like '%s%%'", $key);
                $q1 = $em->createQuery($qstr);
            }
            $res1 = $q1->getSingleResult();
            $count = $res1['bc'];

            // Now get the wanted result specified by page

            $repo = $em->getRepository('trrsywxBundle:BookBook');
            $q2 = $repo->createQueryBuilder('r')
                    ->setMaxResults($rpp)
                    ->setFirstResult(($page - 1) * $rpp)
                    ->orderBy('r.id', 'desc');
            if ($key <> 'null')
            {
                $key = $key . '%';
                $q2->where('r.title like :key')
                        ->setParameter('key', $key);
            }

            $q2 = $q2->getQuery();

            $res2 = $q2->getResult();

            return array($res2, $count);
    }

In the code above, which is a very rep­re­sen­ta­tive code seg­ment for retriev­ing data, I have used 2 ways to gen­er­ate an SQL query and exe­cute it.

One is to use $em->createQuery(), which uses a sim­i­lar gram­mar as we will use when we issue an SQL com­mand in a data­base. The only dif­fer­ence is in the from seg­ment. Instead of using a raw table name (book_book), we use the table class name (trrsywxBundle:BookBook).

getSingleResult is used in my first query as I am expect­ing there will be only one result returned from this query (the count of books match­ing a cer­tain cri­te­ria or ALL books).

In the 2nd query, I used createQueryBuilder and chained all the meth­ods to set nec­es­sary SQL para­me­ters (the start­ing record, the record count, the order, and a where con­di­tion to filter).

getResult is used since we will be expect­ing more than one record.

Finally, we pack the results into an array: $res2 as the resulted dataset and $count as the count of the resulted dataset. They will be fur­ther processed in the call­ing con­troller func­tion (in this case, cre­ate a Pag­i­na­tor object to facil­i­tate the navigation).

Views and Templates

So far we have been doing the “back­ground” work. Noth­ing is pre­sentable with­out a view. In Sym­fony, as in most frame­works, a view is equiv­a­lent to a tem­plate. As I men­tioned ear­lier, Sym­fony uses Twig as its tem­plate engine. It is sim­ple to learn and quick to display.

I will show you a seg­ment of the Twig tem­plate I used to dis­play the Book List page.

(I am not a good web designer, so I slap on Boot­strap 3.0 to quickly boot­strap my page design. You can use your own design or ready-made tem­plates).
Note: below is just a frag­ment of the whole template.

File loca­tion: src/tr/rsywxBundle/Resources/views/Books/List.html.twig

{% set active=2 %}
{% extends 'trrsywxBundle:Default:index.html.twig' %} 

    {% block title %}<title>{{ "RSYWX | Book Collection | Page }}{{cur}}</title>{% endblock %}



{% block content %}
<div class="container">
    <div class="row">
        <div class="col-md-6">
            <h3>My book collection</h3>
        </div>
        <div class="col-md-6">
            <h3>Page {{cur}} of {{total}}</h3>
        </div>
        <div class="col-md-4">
            <form class="form-inline" method="post" action="{{path('books_search')}}" name="searchform" id="searchform">
                <div class="form-group">
                    <input type="text"  class="form-control" required="required" placeholder="Search the beginning of a book title" name="key" id="key" value="{{key}}"/>
                    <input type="hidden" name="cur" id="cur" value="{{cur}}"/>
                </div>
                <button type="submit" class="btn btn-primary">Search</button>

            </form>
        </div>
    <br>
    <div class="row">
        <div class="col-md-12">
            <table class="table table-striped">
                <tbody>
                    <tr>
                        <td><strong>ID</strong></td>
                        <td><strong>Title</strong></td>
                        <td><strong>Author</strong></td>
                        <td><strong>Purchase Date</strong></td>
                        <td><strong>Location</strong></td>
                    </tr>
            {% for book in res %}
                 {% set author=book.author%}
            {%if author ==''%}
            {%set author='(anonymous)'%}
            {%endif%}
                    <tr>
                        <td><a href="{{path('book_detail', {'id':book.id})}}">{{book.id}}</a></td>
                        <td><a href="{{path('book_detail', {'id':book.id})}}">{{book.title}}</a></td>
                        <td>{{author}}</td>
                        <td>{{book.purchdate|date('Y-m-d')}}</td>
                        <td>{{book.location}}</td>
                    </tr>
            {% endfor %}
                </tbody>
            </table>
        </div>
    </div>
    <div class="row">
        <div class="col-md-6">
            <div class="pager">
                <ul>
                    <li class="previous"><a href="{{path('book_list', {'page':1, 'key':key})}}">First</a></li>
                {%if cur==1%}
                        <li class="previous disabled"><a href="{{path('book_list', {'page':cur-1, 'key':key})}}">Previous</a></li>
                {%else%}
                            <li class="previous"><a href="{{path('book_list', {'page':cur-1, 'key':key})}}">Previous</a></li>
                {%endif%}
                {%if cur==total%}
                                <li class="previous disabled"><a href="{{path('book_list', {'page':cur, 'key':key})}}">Next</a></li>
                {%else%}
                                    <li class="previous"><a href="{{path('book_list', {'page':cur+1, 'key': key})}}">Next</a></li>
                {%endif%}
                                        <li class="previous"><a href="{{path('book_list', {'page':total, 'key':key})}}">Last</a></li>
                                    </ul>
                                </div>
                            </div>
                        </div>

                    </div>
{% endblock %}

A few things to dis­cuss here:

  • To dis­play some­thing, use {{obj.member}} nota­tion; to con­trol the flow or manip­u­late data, use {% control statement or manipulation statement %}. Actu­ally, these are the two and only two gram­mar struc­tures in Twig.
  • {% extends %} can be used to extend the page lay­out from a par­ent (base) lay­out. It is very use­ful for page design.
  • {% block title %}...{% endblock %} replaces the con­tent in the par­ent lay­out with your own content.
  • {{path(...)}} is used to gen­er­ate URIs match­ing that route in the tem­plate. It is a very impor­tant helper func­tion that every­one will use. Please also note how the para­me­ters of that route are passed.
  • {% for ... in ... %} is used to iter­ate the result set. It is also very com­monly used.
  • {% set ... %} is used to set a local variable.
  • The rest is reg­u­lar HTML.

Once we run the app, our ren­der should look like some­thing the fol­low­ing figure:

Con­clu­sion

In this part, I have demon­strated how to link up the basic ele­ments in Sym­fony and get your appli­ca­tion up and run­ning. As you can see, the amount of required PHP code was quite min­i­mal. Also, with the help of Boot­strap, the tem­plate code was quite straight­for­ward as well.

In the next and last part of this series, we will cover a few advanced techniques:

  • Pag­i­na­tion
  • Dynam­i­cally add tags asso­ci­ated with a book
  • Dynam­i­cally cre­ate a water mark for the book cover
  • …and more

Stay tuned, and down­load the source code to exper­i­ment on your own!

The post Build­ing a Web App With Sym­fony 2: Devel­op­ment appeared first on Site­Point.

Building a Drupal 7 Module: Show Latest Nodes

Dru­pal is one of the most pop­u­lar open source con­tent man­age­ment sys­tems. It has a lot of func­tion­al­ity built in and thou­sands of free and paid mod­ules to choose from for your site. It has a very exten­si­ble and flex­i­ble archi­tec­ture which lets you build on top of the Dru­pal core and extend its func­tion­al­ity as needed. Dru­pal lets you plug into its sys­tem using Dru­pal hooks. We are going to use some of the hooks in the mod­ule which we are going to build in this arti­cle – a Dru­pal 7 mod­ule to show the dif­fer­ent types of nodes (all con­tent on a Dru­pal web­site is stored and treated as nodes) on your Dru­pal site by cre­at­ing a Dru­pal block. The types of nodes which will be shown can be selected in the con­fig­u­ra­tion menu of the module.

Before we begin, if you don’t have an active Dru­pal instal­la­tion on your machine, please set one up by fol­low­ing the instruc­tions in their instal­la­tion guide.

Build­ing your module’s basic structure

Let’s start by cre­at­ing the basic folder struc­ture and files for our mod­ule. A Dru­pal mod­ule needs to be placed in a spe­cific direc­tory in your Dru­pal instal­la­tion and it needs to have some basic files so that it can be iden­ti­fied as a mod­ule by the Dru­pal sys­tem. The first thing we need to do is cre­ate a folder for our mod­ule called shownodes. That folder should be kept in the sites\all\modules\custom\ folder of your Dru­pal instal­la­tion. In this folder cre­ate two blank files called shownodes.info and shownodes.module.

The file shownodes.info pro­vides the gen­eral infor­ma­tion about your mod­ule to Dru­pal and the file shownodes.module will con­tain the imple­men­ta­tion for var­i­ous hooks used by our mod­ule. The fol­low­ing is how the file struc­ture should look for our module.

Now open the shownodes.info file and add the fol­low­ing content:

name = shownodes
description = This module displays various nodes in a block on your Drupal site.
core = 7.x

This basi­cally describes your module’s basic prop­er­ties like its name, descrip­tion and on which Dru­pal core level it can be deployed. Once you have added these details to the shownodes.info file you should be able to see your mod­ule in the mod­ule list as shown below. You can enable your mod­ule now.

Under­stand­ing Dru­pal Hooks

The sys­tem to extend Dru­pal is built com­pletely on the con­cept of hooks. Hooks are based on nam­ing. For a mod­ule to imple­ment a hook in Dru­pal, it has to cre­ate a func­tion called modulename_hookname depend­ing on which hook it needs to imple­ment in the .module file. Once there is an event to call the hooks, the Dru­pal sys­tem will call the hook imple­men­ta­tion of all the enabled mod­ules. To read more about the avail­able hooks visit the hooks doc­u­men­ta­tion page.

The first hook we will imple­ment in our mod­ule is the hook_help which lets you pro­vide help text on your mod­ule to describe what your mod­ule does.

Add the fol­low­ing code to your shownodes.module file

<?php
/**
 * @file
 * This is the main module file.
 */

/**
 * Implements hook_help().
 */
function shownodes_help($path, $arg) {

  if ($path == 'admin/help#shownodes') {
    $output = '<h3>' . t('About') . '</h3>';
    $output .= '<p>' . t('The shownodes module allows the Administrator to display various types of nodes as a block on your Drupal site.') . '</p>';
    return $output;
  }
}

We are imple­ment­ing the hook_help hook through a func­tion called shownodes_help which returns the help text for our mod­ule when­ever the help request is fired. Once you have imple­mented this hook the help option will be shown on the mod­ule and click­ing it will show the help as follows.

Adding con­fig­u­ra­tion options to your Module

Now let’s add some con­fig­u­ra­tion options for the admin­is­tra­tor of our site. We will cre­ate an options page for the Admin­is­tra­tor so that he can select which node types he wants to dis­play in the block. This can be done using the Dru­pal menu hooks. We will imple­ment the hook_menu hook in our shownodes.module like so:

/**
* Implementation of hook_menu().
*/
function shownodes_menu() {

  $items['admin/config/shownodes'] = array(
  'title' => t('Choose the nodes to show'),
  'description' => t('You can select which node types you want to show'),
  'page callback' => 'system_admin_menu_block_page',
  'access arguments' => array('administer site configuration'),
  'file' => 'system.admin.inc',
  'file path' => drupal_get_path('module', 'system'),
  );

  $items['admin/config/shownodes/settings'] = array(
  'title' => t('Choose the nodes to show'),
  'description' => t('You can select which node types you want to show'),
  'page callback' => 'drupal_get_form',
  'page arguments' => array('shownodes_admin_settings'),
  'access arguments' => array('administer site configuration'),
  'type' => MENU_NORMAL_ITEM,
  );

  return $items;
}

function shownodes_admin_settings() {

  $types = node_type_get_types();
  foreach($types as $node_type) {
    $nodetypes[$node_type->type] = $node_type->name;
  }

  $form['shownodes_nodes_toshow'] = array(
  '#type' => 'checkboxes',
  '#title' => t('Select the nodes to show'),
  '#options' => $nodetypes,
  '#default_value' => variable_get('shownodes_nodes_toshow', array('')),
  '#description' => t('All the node types selected below will be shown'),
  );

  return system_settings_form($form);
}

You can read more about hook_menu at the afore­men­tioned hooks docs page.

In this case, we cre­ate two menu items at the path admin/config/shownodes and admin/config/shownodes/settings and then we build a form with the help of drupal_get_form which cre­ates check boxes for all the installed node types which we get from the Dru­pal func­tion node_type_get_types. Sav­ing the form, Dru­pal will auto­mat­i­cally store the selected val­ues in a vari­able using variable_set with the name taken from the form ele­ment which in our case is shownodes_nodes_toshow. We can fetch the value of this using the func­tion variable_get('shownodes_nodes_toshow', array('')).

We will use this to set the default val­ues in the form and then later in the block imple­men­ta­tion below to show the selected node types. Once we have added the above func­tions we should be able to see our con­fig­u­ra­tion option as shown below in the Administration->configuration option.

Select­ing this option will show us our form with all the node types in the Dru­pal sys­tem and we will be able to select and save the node types which we want to show on our block as shown below.

Cre­at­ing lat­est node Block

Once our con­fig­u­ra­tion is saved we will build our block to dis­play the node types which were selected in the con­fig­u­ra­tion. To cre­ate a block we will imple­ment the hooks hook_block_info and hook_block_view as shown below.

/**
 * Implements hook_block_info().
 */
function shownodes_block_info() {
  $blocks = array();

  $blocks['shownodeblock'] = array(
    'info' => t('A block to show selected nodes'),
    'cache' => DRUPAL_NO_CACHE,
  );

  return $blocks;
}

/**
 * Implements hook_block_view().
 */
function shownodes_block_view($block_name = '') {
  if ($block_name == 'shownodeblock') {

    //Get the selected node types and create a list of them
    $show_nodes_list = array();
    $show_nodes_array = variable_get('shownodes_nodes_toshow', array(''));
    foreach ($show_nodes_array as $key => $value) {
      if($value) {
          array_push($show_nodes_list,$value);
      }
    }

    //Based on the node types create a query and then load the node types
    $query = new EntityFieldQuery();
    $query
    ->entityCondition('entity_type', 'node')
    ->entityCondition('bundle', $show_nodes_list)
    ->propertyCondition('status', 1)
    ->propertyOrderBy('created', 'DESC');

    $result = $query->execute();
    $nodes = array();
    if (isset($result['node'])) {
      $nids = array_keys($result['node']);
      $nodes = entity_load('node', $nids);
    }

    //Loop through the loded nodes to create a list
    //Which we will pass to the theme
    $list = array();
    $i = 0;
    foreach ($nodes as $node) {
      $options = array('absolute' => TRUE);
      $url = url('node/' . $node->nid, $options);
      $list[$i] = '<a href='.$url.'>'.$node->title.'</a>';
      $i++;
    }

    //Return the content of the block
    $theme_args = array('items' => $list, 'type' => 'ol');
    $content = theme('item_list', $theme_args);

    $block = array(
      'subject' => t('Show Nodes Block'),
      'content' => $content,
    );
    return $block;
  }
}

In the above code we define a new block called shownodeblock in the func­tion shownodes_block_info. Then, in the func­tion shownodes_block_view we pro­vide the view for that block by first read­ing the val­ues which were saved in the con­fig­u­ra­tion using the func­tion variable_get('shownodes_nodes_toshow', array(''));. Next we query Dru­pal to get the node IDs based on the node types using the EntityFieldQuery class. Finally, we load those nodes and then loop through them to show them on our block.

Once we have added the above code we should see our block in the block list. You can place the block in one of the regions (regions are actual parts of your lay­out, essen­tially, loca­tions for blocks)

Once the block is placed in one of the regions it can be seen in the region dis­play­ing the node types as follows

Con­clu­sion

In this arti­cle we cre­ated a com­plete Dru­pal mod­ule from scratch. We used dif­fer­ent Dru­pal hooks and Dru­pal func­tions to cre­ate a con­fig­u­ra­tion page and to cre­ate a block which we can place on a region. Dru­pal pro­vides a vari­ety of hooks which can be used to cus­tomize and pro­vide addi­tional func­tion­al­ity over the core. Through this short and fun tuto­r­ial, we’ve proven the exten­si­ble nature of Dru­pal makes expand­ing on it an easy and pleas­ant task. If you’d like to check out the full source code of this mod­ule, please see the Github repo.

The post Build­ing a Dru­pal 7 Mod­ule: Show Lat­est Nodes appeared first on Site­Point.

Building a Live-score Widget Using PHP Web Sockets

The intro­duc­tion of web sock­ets makes it pos­si­ble for web appli­ca­tions to han­dle near real-time data with­out resort­ing to “hacks” such as long-polling.

One exam­ple of an appli­ca­tion requir­ing up-to-the-minute data is sports scores. Even now, many web­sites which dis­play this infor­ma­tion use Flash appli­ca­tions, since Action­script pro­vides the facil­ity to com­mu­ni­cate over socket-based con­nec­tions. How­ever, web sock­ets allow us to repli­cate this func­tion­al­ity using only HTML and Javascript. That’s what we’re going to build in this tuto­r­ial, along with a light­weight “server” in PHP.

image

Instal­la­tion and Setup

We’ll base the exam­ple around the Ratchet library, which pro­vides a PHP imple­men­ta­tion of web sockets.

Cre­ate the fol­low­ing composer.json file, which both installs this depen­dency and sets up an autoloader for the code we’re going to write:

{
    "require": {
        "cboden/Ratchet": "0.2.*"
    },
    "autoload": {
        "psr-0": {
            "LiveScores": "src"
        }
    }    
}

Now set up the direc­tory structure:

[root]
    bin
    src
        LiveScores
    public
        assets
            css
                vendor
            js
                vendor
    vendor

You’ll prob­a­bly want to clone the repos­i­tory, which con­tains a num­ber of CSS / JS / image assets, as well as all the code from this tuto­r­ial. If you’d like to build it from scratch along­side this arti­cle, all you need to do is copy the public/assets/*/vendor fold­ers from the cloned/downloaded pack­age into your own at the appro­pri­ate locations.

Nat­u­rally, don’t for­get to run php composer.phar update, pre­ceded by curl -sS https://getcomposer.org/installer | php if you don’t have com­poser installed.

We’ll start by build­ing a class which resides on the server and acts as a sort of mes­sage bro­ker – accept­ing con­nec­tions and send­ing mes­sages. Later, we’ll also use it to main­tain infor­ma­tion about the games in progress. This is a skele­ton imple­men­ta­tion, to show how a generic mes­sage bro­ker might operate:

// src/LiveScores/Scores.php

<?php namespace LiveScores;

use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;

class Scores implements MessageComponentInterface {

    private $clients;    

    public function __construct() 
    {    
        $this->clients = new \SplObjectStorage;
    }

    public function onOpen(ConnectionInterface $conn) 
    {
        $this->clients->attach($conn);
    }

    public function onMessage(ConnectionInterface $from, $msg) 
    {            
        foreach ($this->clients as $client) {
            if ($from !== $client) {
                // The sender is not the receiver, send to each client connected
                $client->send($msg);
            }
        }
    }

    public function onClose(ConnectionInterface $conn) 
    {
        $this->clients->detach($conn);
    }

    public function onError(ConnectionInterface $conn, \Exception $e) 
    {     
        $conn->close();
    }


}

Impor­tant points to note;

  • The class needs to imple­ment MessageComponentInterface in order to act as a “mes­sage broker”
  • We’re main­tain­ing a list of all clients that have con­nected to the server as a collection
  • When a client con­nects, the onOpen event gets fired, where we add the client to our collection
  • When a client dis­con­nects (onClose), we do the opposite
  • The inter­face also requires us to imple­ment a sim­ple error han­dler (onError)

Next up, we need to cre­ate a server dae­mon to instan­ti­ate our new class and start lis­ten­ing to con­nec­tions. Cre­ate the fol­low­ing file:

// bin/server.php

<?php
use Ratchet\Server\IoServer;
use Ratchet\WebSocket\WsServer;
use LiveScores\Scores;

require dirname(__DIR__) . '/vendor/autoload.php';

$server = IoServer::factory(
    new WsServer(
        new Scores()
    )
    , 8080
);

$server->run();

This should all be pretty self-explanatory; WsServer is an imple­men­ta­tion of the more generic IoServer which com­mu­ni­cates using web sock­ets, and we’ll set it lis­ten­ing on port 8080. You’re free to choose a dif­fer­ent port, of course – pro­vided it’s not blocked by your fire­wall – but 8080 is usu­ally a pretty safe bet.

Main­tain­ing State

We’ll let the server keep track of the cur­rent state of the games; no need to com­mit it to stor­age, we’ll sim­ply keep it in mem­ory for opti­mum per­for­mance. Each time an event takes place in one of the games, we’ll update the scores on the server and then broad­cast the event to all lis­ten­ing clients.

First, though, we need to gen­er­ate the fix­tures (i.e. the list of games). For sim­plic­ity we’ll do it at ran­dom, and just keep this set of fix­tures active for the dura­tion of the daemon’s execution.

// src/LiveScores/Fixtures.php
<?php namespace LiveScores;

class Fixtures {

    public static function random()
    {
        $teams = array("Arsenal", "Aston Villa", "Cardiff", "Chelsea", "Crystal Palace", "Everton", "Fulham", "Hull", "Liverpool", "Man City", "Man Utd", "Newcastle", "Norwich", "Southampton", "Stoke", "Sunderland", "Swansea", "Tottenham", "West Brom", "West Ham");

        shuffle($teams);

        for ($i = 0; $i <= count($teams); $i++) {
            $id = uniqid();
            $games[$id] = array(
                'id' => $id,
                'home' => array(
                    'team' => array_pop($teams),
                    'score' => 0,
                ),
                'away' => array(
                    'team' => array_pop($teams),
                    'score' => 0,
                ),
            );
        }

        return $games;
    }


}  

Note that we’re assign­ing each game a unique iden­ti­fier, which we’ll use later to indi­cate which game an event has taken place in. Going back to our Scores class:

// src/LiveScores/Scores.php

public function __construct() {

    // Create a collection of clients
    $this->clients = new \SplObjectStorage;

    $this->games = Fixtures::random();
}

Because a client could call upon our wid­get at any stage dur­ing a game, it’s impor­tant that they get up-to-the-minute infor­ma­tion. One way to do this is sim­ply to “reply” to a new con­nec­tion request by send­ing the cur­rent state of the games, then ren­der­ing the list of games and their scores client-side.

Here’s the onOpen imple­men­ta­tion, which does just that:

// src/LiveScores/Scores.php

public function onOpen(ConnectionInterface $conn) {
    // Store the new connection to send messages to later
    $this->clients->attach($conn);

    // New connection, send it the current set of matches
    $conn->send(json_encode(array('type' => 'init', 'games' => $this->games)));

    echo "New connection! ({$conn->resourceId})\n";
}

Note that the mes­sage we’re send­ing is actu­ally a JSON object, with the type of event set as a prop­erty. There’s no require­ment to send mes­sages using JSON – you can send any for­mat you wish – but doing it in this way allows us to send dif­fer­ent types of struc­tured messages.

The HTML

Because we’re going to load in the cur­rent scores over a web socket and ren­der them using Javascript, the HTML for the page to start with is very simple:

<div id="scoreboard">

    <table>

    </table>

</div>

Once ren­dered, a row in the score-table will look like this:

<tr data-game-id="SOME-IDENTIFIER">
    <td class="team home">
        <h3>HOME TEAM NAME</h3>
    </td>
    <td class="score home">
        <div id="counter-0-home"></div>
    </td>
    <td class="divider">
        <p>:</p>
    </td>
    <td class="score away">
        <div id="counter-0-away"></div>
    </td>
    <td class="team away">
        <h3>AWAY TEAM NAME</h3>
    </td>
</tr>

The counter-*-* ele­ments are place­hold­ers for a JS plu­gin we’re going to use to ren­der a fancy score wid­get later.

The JavaScript

Now let’s start build­ing the JS. The first thing to do is open a web socket:

var conn = new WebSocket('ws://localhost:8080');

You may need to sub­sti­tute the host­name and / or the port num­ber, depend­ing on where your “server” is running.

Next, attach an event han­dler to the con­nec­tion, which fires when­ever a mes­sage is received:

conn.onmessage = function(e) {    

The mes­sage itself is pro­vided as a data prop­erty to the event e. Because we’re send­ing mes­sages in JSON for­mat, we’ll need to parse it first:

var message = $.parseJSON(e.data);

Now we can exam­ine the type, and call the appro­pri­ate function:

switch (message.type) {
    case 'init':
        setupScoreboard(message);
        break;
    case 'goal':
        goal(message);
        break;
}

The setupScoreboard func­tion is pretty straightforward:

function setupScoreboard(message) {

    // Create a global reference to the list of games
    games = message.games;

    var template = '<tr data-game-id="{{ game.id }}"><td class="team home"><h3>{{game.home.team}}</h3></td><td class="score home"><div id="counter-{{game.id}}-home" class="flip-counter"></div></td><td class="divider"><p>:</p></td><td class="score away"><div id="counter-{{game.id}}-away" class="flip-counter"></div></td><td class="team away"><h3>{{game.away.team}}</h3></td></tr>';

    $.each(games, function(id){        
        var game = games[id];                
        $('#scoreboard table').append(Mustache.render(template, {game:game} ));        
        game.counter_home = new flipCounter("counter-"+id+"-home", {value: game.home.score, auto: false});
        game.counter_away = new flipCounter("counter-"+id+"-away", {value: game.away.score, auto: false});
    });

}

In this func­tion we’re sim­ply iter­at­ing through the array of games, using Mus­tache to ren­der a new row to be added to the score­board table, and instan­ti­at­ing a cou­ple of ani­mated coun­ters for each one. The games array is going to store the cur­rent state of the games client-side, and includes ref­er­ences to those coun­ters so we can update them as required.

Next up, the goal func­tion. The mes­sage we receive over the web socket to indi­cate a goal will be a JSON object with the fol­low­ing structure:

{
    type: 'goal',
    game: 'UNIQUE-ID',
    team: 'home'
}

The game prop­erty con­tains the unique iden­ti­fier, and team is either “home” or “away”. Using these bits of infor­ma­tion, we can update the rel­e­vant score in the games array, find the appro­pri­ate counter object and incre­ment it.

function goal(message) {    
    games[message.game][message.team]['score']++;
    var counter = games[message.game]['counter_'+message.team];
    counter.incrementTo(games[message.game][message.team]['score']);
}

All that remains is some way of indi­cat­ing that a goal has been scored. In order to keep things sim­ple, we’ll just add that to the client; click­ing a team’s name will indi­cate that they’ve scored. In prac­tice you’d have a sep­a­rate appli­ca­tion or page, but the prin­ci­ple is the same. We’ll sim­ply add a click han­dler as fol­lows, which sends a sim­ple JSON mes­sage over the web socket:

$(function () {

    $(document).on('click', '.team h3', function(e){
        var game = $(this).parent().parent().attr('data-game-id');        
        var team = ($(this).parent().hasClass('home')) ? 'home' : 'away';
        conn.send(JSON.stringify({ type: 'goal', team: team, game: game }));
    });

});

The server “lis­tens” for these mes­sages, and if it receives word of a goal it updates its record. All mes­sages received are imme­di­ately re-broadcast to all con­nected clients.

// src/LiveScores/Scores.php
public function onMessage(ConnectionInterface $from, $msg) {

    foreach ($this->clients as $client) {        
        $client->send($msg);            
    }

    $message = json_decode($msg);

    switch ($message->type) {
        case 'goal':
            $this->games[$message->game][$message->team]['score']++;
            break;
    }

}

Finally, to get it up-and-running, you’ll need to launch the server from the command-line:

php bin/server.php

That’s it – try open­ing a cou­ple of win­dows side-by-side, and click­ing a team name to indi­cate a goal. You should see the score­board update straight away!

Con­clu­sion

In this arti­cle, I’ve demon­strated a sim­ple HTML and Javascript “live scores” wid­get using web sock­ets. It has its lim­i­ta­tions; nor­mally you’d expect to see the goalscorer and the time each goal was scored, as well as addi­tional infor­ma­tion such as book­ings and sending-offs. How­ever, because we’re using a JSON object to rep­re­sent an event, such fea­tures should be rel­a­tively straight­for­ward to add. A live demo of this tuto­r­ial is available.

(Note: The Javascript and styles for the coun­ters are thanks to Chris Nan­ney, and come from this post.)

The post Build­ing a Live-score Wid­get Using PHP Web Sock­ets appeared first on Site­Point.

Talk PHP with the Experts:The Transcript

Talk with the Experts this morn­ing was a busy one, with close to a record num­ber of atten­dees. Hardly sur­pris­ing really, con­sid­er­ing that the sub­ject was PHP. Luck­ily for me, the experts were our very own devel­op­ers Jude Aak­jaer and Michael Sauter, and they were super quick off the mark. I didn’t even have to queue the ques­tions. Too easy.

The thing that excited me the most about the chat was that we finally got to use the code win­dow that I com­mis­sioned months ago, and it was a huge suc­cess. If you read through the tran­script below, you’ll see the code saved to Gists through­out the dialogue.

The ses­sion next week is likely to be another pop­u­lar one – I’ll be talk­ing with Wave Digital’s Matt Evans about Devel­op­ing Mobile Appli­ca­tions. That ses­sion will take place at 1:30pm PDT on Wed 23 Oct and you can join the ses­sion here.

If you missed the talk this morn­ing because you didn’t know about it, make sure you sign up for email noti­fi­ca­tions of future ses­sions here.

And if you want to see what went down today, you can read the full tran­script here:

[20:28] <john­lacey> What’s the most impor­tant a begin­ner to PHP needs to know to get started?
[20:30] <san­touras> john­lacey: like learn­ing any new thing, I think its pretty impor­tant to be get­ting taught by some­one who knows what they’re doing
[20:30] <weebit> Is learn­ing PHP a good thing to do for any­one want­ing to make themes for CMS’s?
[20:31] <john­lacey> I notice a lot of people/sites rec­om­mend XAMPP for Win­dows based local devel­op­ment (includ­ing Sitepoint’s Kevin Yank). Am I miss­ing out on any­thing by using WAMP instead?
[20:31] <michael­sauter> @johnlacey I think there is noth­ing par­tic­u­lar that one needs to know to get started. PHP is one of the lan­guages that is really easy to get into and there is lots of tuto­ri­als etc. on the web. i would say that’s one of the prob­lems too: there is a lot of old/outdated/bad infor­ma­tion out there
[20:31] <michael­sauter> @weebit yes, def­i­nitely
[20:31] <michael­sauter> weebit lots of CMS are writ­ten in PHP, so know­ing some PHP to write tem­plates will be help­ful
[20:31] <san­touras> john­lacey I’d rec­om­mend using a vir­tual machine setup per­son­ally instead of xampp/wampp
[20:32] <HAWK> I’ll plug our pop­u­lar PHP course https://​learn​able​.com/​c​o​u​r​s​e​s​/​p​h​p​-​m​y​s​q​l​-​w​e​b​-​d​e​v​e​l​o​p​m​e​n​t​-​f​o​r​-​b​e​g​i​n​n​e​r​s​-13
[20:32] <san­touras> almost all deploy­ment is on linux machines and if you’re cod­ing on win­dows, it is far eas­ier to have your dev envi­ron­ment mach your pro­duc­tion envi­ron­ment
[20:33] <san­touras> if you’re cod­ing on osx/linux then dev on your local machine becomes more attrac­tive but I’d never code php directly onto win­dows again
[20:33] <bobo> hello every­body! how would you pre­vent post data being resub­mit­ted on refresh/navigation?
[20:34] <michael­sauter> same here. always bet­ter to have a portable vir­tual machine for dev around
[20:34] <evil­nick> PHP is evil!
[20:34] <Brad82> I sec­ond not cod­ing php directly on win­dows.
[20:34] <McGeough> 1) which is the most used devel­op­ment using PDO or MySQLi? and 2) Which is the best frame­work around? Codeigniter, lar­avel, zend etc
[20:35] <san­touras> @bobo this is more of a browser ques­tion :) but some strate­gies include pro­cess­ing the data on post and then for­ward­ing the user to a results page
[20:35] <HAWK> Wel­come if you just joined. Jump in with ques­tions at any time. :)
[20:35] <san­touras> @McGeough I tend to use PDO when I’m not using an abstrac­tion layer
[20:35] <evil­nick> McGeough PDO is bet­ter because it pro­vides some level of abstrac­tion, so you can use any data­base you want
[20:35] <michael­sauter> McGeough 2) depends very much on your pref­er­ence. i per­son­ally favour Symfony2
[20:35] <Brad82> McGeough 2) is a very sub­jec­tive ques­tion, some are more suit­able than oth­ers for dif­fer­ent cir­cum­stances. I’m a fan of FuelPHP per­son­ally
[20:35] <san­touras> the frame­work ques­tion is like a reli­gious argu­ment
[20:35] <evil­nick> also MySQL kinda sucks, try Post­greSQL
[20:36] <McGeough> Ive heard of Symfony2 but never got look­ing at it
[20:36] <Ick­leChris> 2) is def­i­nitely project based. It’s like try­ing to decide what size gun to use to shoot a mouse
[20:36] <weebit> So how far up the lad­der in PHP in learn­ing should I go if I am just learn­ing PHP for themes? Is there a cer­tain part of PHP I should learn?
[20:37] <san­touras> @McGeough I’ve recently been using Silex which is a trimmed down ver­sion of symfony2, def­i­nitely handy for small projects
[20:37] <michael­sauter> to fig­ure out “which frame­work should i use”, I think it’s best to look first at your require­ments, then what cod­ing style / approach you like and maybe also who you want to work with, then pick a frame­work
[20:37] <Paul> Does PDO work with mon­goDB
[20:37] <san­touras> @weebit what kind of them­ing are you refer­ring to? which plat­form specif­i­cally?
[20:37] <evil­nick> Paul of course not, PDO is for SQL
[20:37] <weebit> Word­Press and maybe Joomla later on
[20:38] <HAWK> If you just got here, hi. :) Feel free to join in with ques­tions when you’re ready
[20:38] <McGeough> Also which tem­plat­ing engines are best for PHP, so far ive been using Smarty through work and we are won­der­ing if there is any­thing bet­ter and faster?
[20:38] <michael­sauter> So Word­Press uses PHP in a very …. let’s say … inter­est­ing … way. Not too much learn to fig­ure out what’s hap­pen­ing in tem­plates
[20:39] <san­touras> McGeough I’ve been a fan of smarty in the past and used it in a lot of projects. Twig is sim­i­lar in syn­tax and is also worth look­ing at
[20:39] <michael­sauter> McGeough again, tempt­ing is also a mat­ter of pref­er­ence. I’m again in favour of Twig
[20:39] <sh4d0ws> i think that we need to think about which one will con­tinue hav­ing suport in the future… 1 or 2 year… because if we take a lot of time learn­ing and devel­op­ing some­thing and then after 2 or 3 year the frame­work is “dead”, its worth­less
[20:39] <Brad82> What advan­tages is there over using a tem­plat­ing engine over just plain old PHP in tem­plates
[20:39] <McGeough> san­touras michael­sauter is twig any faster or light­weight etc?
[20:40] <michael­sauter> In Twig you don’t have to / can’t write any PHP, but it’s still very fast as it com­piles to PHP
[20:40] <Brad82> Of course I only mean echo and fore­ach() for exam­ple in tem­plates.
[20:40] <san­touras> Brad82 the biggest advan­tage is sep­a­ra­tion of con­cern
[20:40] <evil­nick> Brad82 well, they’re not as ugly as PHP
[20:40] <john­lacey> I realise this is a very subjective/personal thing… but just out of curios­ity what’s your pre­ferred code edi­tor?
[20:40] <san­touras> it clearly defines the logic and pre­sen­ta­tional aspects of your appli­ca­tion
[20:40] <clif­fgs> Net Beans is my pre­ferred edi­tor
[20:40] <Ick­leChris> I’m an Aptana Stu­dio guy
[20:40] <san­touras> john­lacey my per­sonal is ST2, and ST3 when it becomes sta­ble, but I use vim from time to time
[20:41] <McGeough> ST2
[20:41] <Brad82> ST2 for me also
[20:41] <McGeough> ST3 just isnt sta­ble enough right now
[20:41] <sh4d0ws> any­one now how to get all par­ti­tions in nix from PHP with­out pars­ing “df” ?
[20:41] <evil­nick> Sub­lime and vim are the best
[20:41] <pro­gram­mer> My ques­tion is about secu­rity. I am con­nect­ing to a MySQL data­base, and I have the con­nec­tion con­stants in a sep­a­rate file. Should I place that file out­side the doc­u­ment root, just to be sure? And if so, how do I ref­er­ence it?
[20:41] <michael­sauter> i used to code a lot in PHP­Storm, now using Sub­lime
[20:42] <Brad82> McGeough I’ve been using ST3 for months now and it hasnt crashed on me once (touch­wood)
[20:42] <sh4d0ws> ST2 :D
[20:42] <san­touras> pro­gram­mer absolutely. If at all pos­si­ble the only code in the web root should be the boot­strap­ping index.php file and any pub­lic assets
[20:42] <san­touras> almost all mod­ern frame­works oper­ate like this
[20:43] <michael­sauter> pro­gram­mer PHP can still include that file, but there is a set­ting in php.ini which allows/denies this. I think it’s on by default
[20:43] <pro­gram­mer> I haven’t been able to find an exam­ple of this, how­ever. I am using IIS.
[20:43] <McGeough> Brad82 ive used it a few times and it did crash, maybe i just had bad luck, but will be upgrad­ing
[20:43] <san­touras> pro­gram­mer are you deploy­ing to IIS or just using that for devel­op­ment?
[20:43] <san­touras> wel­come Mal­Cur­tis :)
[20:44] <Mal­Cur­tis> Thanks! I have to say the two experts have very hand­some pro­file pics
[20:44] <amir> ST3 is good in terms of speed
[20:44] <pro­gram­mer> I’m actu­ally using apache for local devel­op­ment, but have a true devel­op­ment envi­ron­ment in IIS. Pro­duc­tion is IIS.
[20:44] <amir> but some­thing is still miss­ing
[20:44] <Brad82> I still have night­mares about using IIS at work for pro­duc­tion.
[20:44] <san­touras> Brad82 me too :( and I haven’t had to deploy to IIS in around 8 years!
[20:44] <pro­gram­mer> I’m not too crazy about IIS myself, but the project is an addi­tion to an exist­ing site, so I don’t have much choice.
[20:45] <HAWK> Yay! The code edi­tor!
[20:45] <san­touras> magic is hap­pen­ing
[20:45] <Brad82> pro­gram­mer is it IIS7 you are deploy­ing to?
[20:45] <john­lacey> I don’t think I’ve ever seen any­one use the code edi­tor in here before. lol. Excit­ing times.
[20:45] <McGeough> Slightly off topic but for those using Ver­sion Con­trol would you ever take your whole projects (all projects on sys­tem) folder as a repos­i­tory or sep­a­rate repos­i­tory for each project
[20:46] <san­touras> sep­a­rate repo
[20:46] <HAWK> I know john­lacey! I chal­lenged the guys to use it ;)
[20:46] <McGeough> whos the magi­cian using it?
[20:46] <san­touras> McGeough most of my php projects these days use com­poser so this is very nat­ural
[20:46] <san­touras> michael­sauter I believe!
[20:47] <McGeough> com­poser?
[20:47] <michael­sauter> yup that’s me
[20:47] <evil­nick> can’t edit in the code edi­tor :| how do we use it
[20:47] <michael­sauter> for­got how to write con­stants out­side a class :D
[20:47] <Brad82> evil­nick ask HAWK
[20:47] <san­touras> http://​get​com​poser​.org/
[20:47] <san­touras> basi­cally PHP’s ver­sion of bundler
[20:47] <pro­gram­mer> so rel­a­tive ../ path from where I start? I assume I have to go all the way up from wher­ever the code is.
[20:48] <michael­sauter> yea in my exam­ple your doc­u­ment root is htdocs/
[20:48] <michael­sauter> config/ is not acces­si­ble by IIS
[20:48] <evil­nick> IIS sucks
[20:48] <san­touras> the rubygems equiv­a­lent is https://​pack​ag​ist​.org/
[20:48] <san­touras> evil­nick this has been estab­lished and agreed upon
[20:49] <pro­gram­mer> I wish I didn’t have to use IIS
[20:49] <san­touras> almost all actively devel­oped php projects are avail­able on pack­ag­ist
[20:49] <pro­gram­mer> I don’t think try­ing to mix two web servers is a good idea, though.
[20:49] <san­touras> if you’re putting together a new project, you should def­i­nitely give it a look, it will make using exter­nal libraries a lot eas­ier
[20:50] <pro­gram­mer> thanks
[20:51] <michael­sauter> Saved edi­tor: https://​gist​.github​.com/​6​9​9​8​459
[20:51] <evil­nick> HAWK can I use the edi­tor?
[20:52] <HAWK> Yup evil­nick – give it a go now
[20:52] <pro­gram­mer> must run a quick errand. back later.
[20:52] <michael­sauter> com­poser really is an awe­some project. it also helps with autoload­ing, all that comes with it by default
[20:52] <san­touras> php has made enor­mous strides in the last few years. if things like com­poser and PSR-0 had been around 8 years ago it would have helped a lot
[20:53] <michael­sauter> that’s one of the things which is rel­a­tively new and which might not be men­tioned in a lot of tuto­ri­als, although it is incred­i­bly help­ful to learn after you know some PHP basics
[20:53] <san­touras> and things like boris -> https://​github​.com/​d​1​1​w​t​q​/​b​o​ris
[20:54] <san­touras> wel­come new peo­ple
[20:54] <Paul> I think grunt also fits into this pic­ture
[20:54] <michael­sauter> grunt is more for fron­tend tasks, and is run­ning on nodejs. but def­i­nitely some­thing that makes life a lot eas­ier :)
[20:56] <Ger­win> can we talk about using name­spaces?
[20:56] <san­touras> sure
[20:56] <michael­sauter> sure!
[20:56] <michael­sauter> what would inter­est you?
[20:56] <Brad82> name­spaces <3
[20:57] <Ger­win> i haven’t used them before but i really like what they do, can we go over a good use case, when and when not to use them?
[20:57] <Ger­win> any short falls etc
[20:57] <pamelasue101> I’m lis­ten­ing today, I don’t know what ques­tions to ask and I’m just learn­ing
[20:57] <eip56> Can answer mine after. But hows does every­one feel about get/set meth­ods in PHP OOP. Cre­ate gets and sets or use magic meth­ods?
[20:57] <HAWK> All good pamelasue101 :)
[20:57] <harlem> I wanted to secure this “news.php?news_id=$row[’id’]“, I heard that I could encrypt the id ? Can you some­one guide me with this ? Sorry I speak french my sen­tences will not come gra­mat­i­caly cor­rect
[20:58] <Paul> don’t classes pretty much put name­spaces to the way­side?
[20:58] <Brad82> harlem what advan­tages would you gain by encrypt­ing the ID?
[20:58] <michael­sauter> I think it’s almost always a good idea to use name­spaces, except when you just have maybe 3–4 files
[20:58] <san­touras> Paul, no not really
[20:58] <evil­nick> name­spaces is an attempt to cre­ate some­thing like Mod­ules in Ruby
[20:58] <michael­sauter> if you’re writ­ing a library or using a library you should­def­i­nitely use them
[20:58] <Ger­win> thought as much
[20:59] <Ger­win> to avoid clashes with other com­mon class names?
[20:59] <Ger­win> so
[20:59] <Ger­win> users
[20:59] <Ger­win> would be gerwins_plugin\users
[20:59] <Ger­win> some­thing like that?
[20:59] <michael­sauter> the trick­i­est is to autoload the name­spaces, but there are stan­dards which make that quite easy. so if you stick to those stan­dards you and other libraries can load the classes by default
[20:59] <michael­sauter> see for exam­ple http://​www​.site​point​.com/​a​u​t​o​l​o​a​d​i​n​g​-​a​n​d​-​t​h​e​-​p​s​r​-​0​-​s​t​a​n​d​a​rd/
[20:59] <Ger­win> awe­some
[21:00] <Ick­leChris> I hear a lot about how cre­at­ing a CMS/Framework is a great way to fur­ther develop basic PHP skills.. Is this really a good place to start, and are there any point­ers for this?
[21:00] <san­touras> eip56 I like them in the­ory because it cuts down on the num­ber of acces­sor meth­ods you need to write, but they are slower than direct func­tion calls
[21:01] <Hulkur> Ickle, i don’t rec­om­mend
[21:01] <michael­sauter> @eip56 I per­son­ally pre­fer get/set meth­ods, but they are a bit tedious to write, which is why I pre­fer PHP­Storm when I do exten­sive PHP pro­gram­ming
[21:01] <Brad82> Ick­leChris some say a blog is a good thing to cre­ate if you are new to PHP
[21:01] <michael­sauter> (or some other IDE)
[21:01] <san­touras> Ick­leChris it prob­a­bly isn’t the best idea to cre­ate a cms/framework unless you’ve had exten­sive expe­ri­ence work­ing on one in the past
[21:01] <Hulkur> if you don’t know lan­guage you are not able to use it prop­erly
[21:01] <harlem> I wanted to secure the trans­fer of that infor­ma­tion, I read some­where it can open up for dif­fer­ent attacks
[21:01] <eip56> Also in my opin­ion Ick­leChris pick up like CodeIgniter or some­thing sim­i­lar
[21:01] <michael­sauter> Ger­win yea, but you would use Camel­Case, so GerwinPlugin\Users
[21:01] <san­touras> @harlem it sounds like you’re refer­ring to SQL injec­tion?
[21:01] <Brad82> harlem would the ID be numeric or alphanu­meric?
[21:01] <eip56> it will accel­er­ate your learn­ing curve espe­cially on OOP top­ics
[21:02] <san­touras> @harlem are you using a frame­work or library? or writ­ing all of your code directly
[21:02] <Paul> I’d like to know how to reverse engi­neer word­press so I can see exactly how it works. Any input on that?
[21:02] <Brad82> @paul as a word­press user and lover myself, that is a very… inter­est­ing task
[21:02] <Ger­win> oh right that looks nicer
[21:02] <michael­sauter> Paul Word­Press is open source, so you can just read the code base
[21:02] <san­touras> @Paul https://​github​.com/​W​o​r​d​P​r​e​s​s​/​W​o​r​d​P​r​ess
[21:02] <evil­nick> is my code cor­rect?
[21:03] <michael­sauter> Paul How­ever, I wouldn’t rec­om­mend that :)
[21:03] <harlem> yes
[21:03] <Brad82> Paul learn to love the Word­Press Codex, it is extremely use­ful
[21:03] <eip56> @Paul there is really no need to reverse engi­neer it is well doc­u­mented int he codec
[21:03] <michael­sauter> Word­Press has a lot legacy code …. and is a huge and com­plex sys­tem
[21:03] <evil­nick> haven’t used PHP for a long time, and not going to
[21:03] <san­touras> hmm, I’m not see­ing the code edi­tor update
[21:03] <harlem> the id is numeric
[21:03] <michael­sauter> me nei­ther
[21:04] <HAWK> evil­nick – what code?
[21:04] <evil­nick> hmm
[21:04] <evil­nick> so it doesn’t show up?
[21:04] <eip56> Whats everyone’s favorite IDE… Ive used sev­eral but my main atm is just Pro­gram­mers notepad
[21:04] <san­touras> @harlem are you using a frame­work?
[21:04] <eip56> Id like to find a good one for my Mac
[21:04] <san­touras> eip56 ST2 is pop­u­lar
[21:04] <san­touras> michael­sauter is a fan of php­storm
[21:05] <Hulkur> what’s ST2 ?
[21:05] <HAWK> evil­nick Save it to gist using the set­tings cog and see if we can see it then
[21:05] <evil­nick> Saved edi­tor: https://​gist​.github​.com/​6​9​9​8​654
[21:05] <san­touras> sub­lime text 2
[21:05] <Hulkur> storm is good, net­beans is free
[21:05] <Brad82> harlem, in real­ity I see very lit­tle rea­son to encode the ID. You should focus more on secur­ing your scripts inter­nals so that any­thing the user sets as ID can be parsed securely.
[21:05] <harlem> I read this book PHP Mysql web devel­op­ment
[21:05] <clif­fgs> That’s what I usu­ally do. I con­nect by include_once $_SERVER[’DOCUMENT_ROOT’] . ‘/../code/admindb.inc.php’;
[21:05] <clif­fgs> And Net Beans is cross plat­form
[21:05] <HAWK> Ok, so that worked evil­nick – not sure why we’re not see­ing it live
[21:06] <Hulkur> net­beans is java, so it eats mem­ory
[21:06] <harlem> san­touras I am not using any frame­work
[21:06] <san­touras> harlem the most impor­tant thing is sani­ti­sa­tion of any user input
[21:06] <michael­sauter> Hulkur I think almost all IDEs are Java :(
[21:06] <Brad82> harlem Remem­ber, even if in your app you encode the query string, I can always type into the address bar man­u­ally an exploit, in this case encod­ing it has no effect
[21:06] <Oliv­er­Thomas> Is there any use­ful PHP plu­g­ins for Notepad++?
[21:06] <san­touras> unless you’ve ver­i­fied it, don’t trust it
[21:07] <clif­fgs> Hulkar mem­ory is cheap and plen­ti­ful
[21:07] <san­touras> use a regex to ensure/strip out, any­thing that is not what you’re expect­ing. and if you get funny results, don’t go fur­ther
[21:07] <michael­sauter> Oliv­er­Thomas not sure, i have never used it.
[21:07] <harlem> Brad82 what can I do than I am using a php regex script to make what I $_GET is what I want
[21:08] <Oliv­er­Thomas> Hi michael, i see. what pro­gram do you rec­om­mend for PHP devel­op­ment?
[21:08] <michael­sauter> Give sub­lime text a try, it has lots of plu­g­ins
[21:08] <Hulkur> Mem­ory is plen­ty­ful, but NB still eats it all
[21:08] <Hulkur> and is slow
[21:08] <evil­nick> yea :D
[21:08] <Paul> I don’t know what it’s writ­ten in, but aptana eats mem­ory too
[21:08] <evil­nick> Aptana is Eclipse
[21:08] <Hulkur> storm some­how is faster and less hun­gry
[21:08] <san­touras> aptana is java
[21:08] <Brad82> harlem, you said the ID will be numeric? In that case all you require is to do is_numeric() on the $_GET vari­able, no slow regex required!
[21:08] <Oliv­er­Thomas> Thank you i will check it out
[21:08] <Michael> I use UltraEdit Stu­dio for PHP dev
[21:09] <san­touras> if your sen­tence is “[edi­tor] eats mem­ory” it’s most likely java based ;)
[21:09] <Hulkur> does sub­lime sup­port nav­i­gat­ing to class/function ?
[21:09] <Aaron> I like PHP­Storm
[21:09] <san­touras> yes
[21:09] <san­touras> Hulkur yes
[21:09] <michael­sauter> Yup, so that’s why PHP­Storm was/is my choice, it seemed to be the fastest amongst the heav­ier IDEs. But nowhere near ST or Text­mate etc.
[21:09] <Brad82> hawk can I get edi­tor for a sec?
[21:09] <harlem> Brad82 san­touras
[21:09] <HAWK> It doesn’t seem to be work­ing prop­erly
[21:09] <Oliv­er­Thomas> michael­sauter is it dan­ger­ous to loop through $_POST super­global when pro­cess­ing form data
[21:09] <san­touras> http://​www​.sub​lime​text​.com/ <- go to any­thing
[21:09] <Ger­win> I’m guess­ing most peo­ple here use php­MyAd­min? That right?
[21:10] <harlem> thank you guys Brad82 san­touras any links ?
[21:10] <HAWK> Give it a go now Brad82
[21:10] <michael­sauter> Oliv­er­Thomas not unless you’re doing some­thing with that data like enter­ing it into the data­base
[21:10] <Paul> I just started using vim. it’s pretty pow­er­ful
[21:10] <evil­nick> What the hell am I even doing here, I just remem­bered that I hate PHP :D
[21:10] <michael­sauter> Oliv­er­Thomas what do you want to achieve?
[21:10] <san­touras> Ger­win no, I used SQLYog on windows/linux, and Sequel­Pro on mac
[21:10] <san­touras> I’m aller­gic to php­myad­min :)
[21:10] <Oliv­er­Thomas> I use pre­pared state­ments to insert
[21:10] <Aaron> What’s the best way to ana­lyze code for secu­rity issues? I don’t have the money for Acunetix, are there any other options?
[21:10] <Ger­win> Cool, if any­one is inter­ested, i recently built this http://​cabindb​.com/
[21:11] <Oliv­er­Thomas> just seek­ing advice on the best way to do cer­tain things
[21:11] <Hulkur> new php­myad­min tree is awful
[21:11] <Ger­win> yeah
[21:11] <michael­sauter> Ger­win looks nice!
[21:11] <san­touras> Ger­win nice, very nice, will look at that
[21:11] <Michael> I use Nav­i­cat
[21:11] <san­touras> I almost always pre­fer desk­top apps, but will give that a look
[21:11] <Ger­win> thanks, it’s pretty young and i’d love for peo­ple to try it out, but don’t rely on it yet :)
[21:12] <michael­sauter> Oliv­er­Thomas so your loop­ing over $_POST, and inside the loop using pre­pared state­ments?
[21:12] <Brad82> harlem, check edi­tor as sim­ple as that!
[21:12] <Hulkur> there is some­thing bet­ter than PHP ?
[21:12] <Hulkur> can’t pos­si­bly be
[21:12] <Mal­Cur­tis> Looks good Ger­win (and Hi!)
[21:12] <jae­query> peo­ple still learn PHP?
[21:12] <michael­sauter> Oliv­er­Thomas I’d be very cau­tios even then, maybe bet­ter to just loop over keys you define, and then look up the super­global value from there
[21:13] <Brad82> harlem https://​gist​.github​.com/​6​9​9​8​745
[21:13] <eip56> jae­query you blas­phe­mer
[21:13] <eip56> PHP rocks
[21:13] <Oliv­er­Thomas> michael­sauter no no, I am pro­cess­ing the form data using a fore­ach() to trim the data and then go through each field indi­vid­u­ally check­ing for the var­i­ous require­ments, then includ­ing a pre­pared sta­tee­ment script.
[21:13] <evil­nick> thou shalt use Ruby
[21:13] * evil­nick com­mences the holy war
[21:13] <Ger­win> ruby syn­tax may induce vom­it­ing
[21:13] <san­touras> Aaron have you looked at PHPMD?
[21:13] <jae­query> it was a seri­ous ques­tion :x
[21:13] <san­touras> Ger­win evil­nick there is room in the world for many lan­guages :)
[21:14] <Hulkur> ruby syn­tax does induce vom­it­ing
[21:14] <evil­nick> not for PHP
[21:14] <san­touras> some peo­ple still use cobal
[21:14] <michael­sauter> jae­query I think PHP is not a bad choice. It’s easy to get into, and depend­ing where you live, lots of jobs. Sure other lan­guages have a bet­ter design, but there are lots of apps writ­ten in PHP
[21:14] <Aaron> san­touras I haven’t…
[21:14] <michael­sauter> Oliv­er­Thomas sounds good then
[21:14] <evil­nick> PHP doesn’t even have a nam­ing con­ven­tion
[21:14] <Ger­win> Mal­Cur­tis hey man, saw your name. Yeah it’s a start, with lim­ited amount of spare time I have haha.
[21:14] <jae­query> my php codes are good. i just can’t stand the oth­ers (word­press, dru­pal, joomla, yuck)
[21:14] <Hulkur> evil­nick, you mean not forced upon you nam­ing con­ven­tion
[21:14] <Paul> I havn’t fig­ured out and easy way how to paste code from an out­side file into vim yet other than some long com­mand in a macro
[21:15] <evil­nick> I mean core library nam­ing con­ven­tion
[21:15] <michael­sauter> evil­nick https://​github​.com/​p​h​p​-​f​i​g​/​f​i​g​-​s​t​a​n​d​a​r​d​s​/​b​l​o​b​/​m​a​s​t​e​r​/​a​c​c​e​p​t​e​d​/​P​S​R​-​2​-​c​o​d​i​n​g​-​s​t​y​l​e​-​g​u​i​d​e​.md
[21:15] <Paul> I wish I could in vim
[21:15] <Mal­Cur­tis> Ger­win can you run arbi­trary SQL queries? That’s one of my main uses for any sql tool
[21:15] <Elie> nam­ing con­ven­tion? lol use your own
[21:15] <michael­sauter> PHP has changed in the past few years
[21:15] <Ger­win> Mal­Cur­tis Yes sir, with syn­tax high­light­ing!
[21:15] <Oliv­er­Thomas> Thanks michael for the feed­back
[21:15] <Mal­Cur­tis> sheeet son.
[21:15] <Hulkur> about name­spaces, there is really not use if yoou name your classes some­thing like My_Package_Class
[21:15] <jae­query> hon­estly, i think it has turned for the worst
[21:15] <evil­nick> yeah but it’s no way to deter­mine which func­tion to use because they use dif­fer­rent nam­ing con­ven­tions
[21:15] <Ger­win> And user per­mis­sions are easy to do!
[21:15] <Hulkur> then there is no con­flict
[21:16] <harlem> thanks Brad82
[21:16] <san­touras> Hulkur I would dis­agree, mainly due to code beauty :)
[21:16] <Mal­Cur­tis> Hulkur yea that’s great until you see some big ones
[21:16] <jae­query> the autoloader dis­cus­sion on php-fig sick­ens me
[21:16] <Hulkur> i work on magento, big enough
[21:16] <Ger­win> DL it and try get it going locally, have a play. I haven’t tested on too many machines yet, mac and pc works and my AWS machine too. Still needs more test­ing, all js one page styles
[21:16] * evil­nick rage­quits
[21:16] <HAWK> evil­nick has just rage­quit
[21:17] <Mal­Cur­tis> Like: Sitepoint_Courses_PageController_CourseAdminController
[21:17] <michael­sauter> haha :)
[21:17] <eip56> HAWK this one you prob­a­bly know best but any­one else as well. A lit­tle more gen­eral can any­one rec­om­mend a ser­vice for check­ing cross browser com­pat­i­bil­ity. Hope­fully free but I know there are a few ser­vices where I can check my site in older virtual-ized browsers
[21:17] <san­touras> Mal­Cur­tis :(
[21:17] <Mal­Cur­tis> * insert vomit emoti­con here *
[21:17] <jae­query> what is this cha­t­room made in?
[21:17] <Hulkur> how it’s shorter with name­space ?
[21:17] <Brad82> Mal­Cur­tis I just had a mini stroke look­ing at that
[21:17] <jae­query> is it open­source?
[21:17] <Mal­Cur­tis> when you’re inside a name­space you don’t need to type the whole thing…
[21:17] <pro­gram­mer> Are there any other rec­om­mended checks for get and post vari­ables? I see some­thing in the code win­dow.
[21:17] <michael­sauter> Hulkur you can import name­spaces, and then just use the class name
[21:18] <Mal­Cur­tis> jae­query kinda, I started with kiwi­irc, which is an open source node.js irc client, then added in a bucket load of cus­tomiza­tions
[21:18] <Hulkur> can you show me some cor­rectly made name­spaces
[21:18] <Brad82> pro­gram­mer that was a very sim­pli­fied exam­ple to check if a get var was numeric
[21:18] <michael­sauter> pro­gram­mer so either you’re using a frame­work that does all that for you, or the best is to know what you’re using a vari­able for, and then san­i­tiz­ing it specif­i­cally for that
[21:18] <Hulkur> i think i don’t under­stand them prop­erly yet
[21:19] <san­touras> Saved edi­tor: https://​gist​.github​.com/​6​9​9​8​820
[21:19] <Brad82> pro­gram­mer it depends what you are doing with said vari­able on how you sanitise/verify it
[21:19] <HAWK> Can any­one help out eip56 with good browser com­pat­i­bil­ity test­ing ser­vices?
[21:19] <Hulkur> this is small, how do you place mod­els and views ?
[21:19] <pro­gram­mer> What is the best way to san­i­tize, then? Mostly I have strings.
[21:19] <Hulkur> you still need long names
[21:20] <Hulkur> just / instead of _
[21:20] <Brad82> @hulker
[21:20] <jae­query> is it more rec­om­mended to do Site­point or \Site­point
[21:20] <pro­gram­mer> And most of those should be only a sin­gle char­ac­ter Y or N
[21:20] <michael­sauter> @programmer depends where you want to use that string. when you want to dis­play it, use html­spe­cialchars or sim­i­lar, when for mysql, use some mysql escape func­tion
[21:20] <san­touras> jae­query gen­er­ally you would use Site­point unless you wanted to ensure you hit the root level
[21:21] <pro­gram­mer> OK, I think I’ve got mysqli_real_escape or some­thing like that.
[21:21] <san­touras> jae­query you see this most often with peo­ple explic­itly using the \Excep­tion class
[21:21] <pro­gram­mer> Because they go into a db query
[21:21] <Paul> elp56 I like http://​quirk​tools​.com/​s​c​r​e​e​n​f​ly/
[21:21] <jae­query> why wouldnt you always want to start from root?
[21:21] <Paul> but that’s screen res­o­lu­tion
[21:21] <HAWK> eip56 Are you on Twit­ter? I’ve just tweeted your ques­tion from @sitepointdotcom
[21:22] <michael­sauter> Hulkur see my exten­sion of the code. you can use the short names once you import a name­space at the top of the file
[21:22] <san­touras> jae­query because it resolves to any imported name­spaces
[21:22] <michael­sauter> pro­gram­mer yea that’s good if you use it inside a sql query
[21:22] <AlexF> Another nice ben­e­fit of name­spaces is alias­ing use Some\Other\Namespace as NS;
[21:22] <san­touras> so start­ing from root kind of takes away the whole point of “use”
[21:22] <jae­query> how does name­space han­dle things where you have Site­point\* , and some­one else also has Site­point\* out of sheer luck?
[21:23] <Nofel> i had been fan of php since many years but how can I apply, u can’t get project with­out prov­ing ur a php expert so how u prac­tice a php project to test skills
[21:23] <Brad82> pro­gram­mer run­ning $_REQUEST vari­ables through mysqli_real_escape… is enough before you put it in a SQL query
[21:23] <san­touras> Nofel best thing is to write an appli­ca­tion as a per­sonal project and host the code on github
[21:23] <Paul> elp56 this is free cross­browser http://​browser​shots​.org/
[21:24] <pro­gram­mer> Excel­lent. I also am check­ing length of input.
[21:24] <eip56> HAWK I am 
[21:24] <Hulkur> thou shalt read man­ual ! :) found my miss­ing knowl­edeg use My\Full\Classname as Another;
[21:24] <eip56> :-( and i thought we were friends!
[21:24] <Nofel> san­touras u mean make ur own project?
[21:24] <michael­sauter> jae­query that’s a prob­lem then. how­ever, if you fol­low stan­dards and upload your library to pack​ag​ist​.org, that shouldn’t hap­pen
[21:24] <Hulkur> name­space alias­ing and no long names any­more
[21:24] <Nofel> what is
[21:24] <san­touras> jae­query the doc­u­men­ta­tion cov­ers res­o­lu­tion – http://​php​.net/​m​a​n​u​a​l​/​e​n​/​l​a​n​g​u​a​g​e​.​n​a​m​e​s​p​a​c​e​s​.​r​u​l​e​s​.​php
[21:24] <Brad82> pro­gram­mer first run all the vari­ables through your mysql_escape… and then use those cleaned vari­ables in strlen($var) checks after­wards
[21:24] <jae­query> thats why im con­fused , isnt the puprose of name­space to avoid col­li­sion when there is one?
[21:25] <Mal­Cur­tis> The pur­pose is to pro­vide an encap­su­lated and insu­lated place to write a pack­age of code, which hap­pens to avoid col­li­sions as a part of it
[21:25] <michael­sauter> Hulkur afaik this only aliases the name­space, not the class
[21:25] <Hulkur> yes, but then you use alias as short name­space
[21:26] <san­touras> Nofel yes, writ­ing your own project as a sam­ple appli­ca­tion
[21:26] <Nofel> I fol­low the php train­ing by Kevin skoug­land on Lynda. He do refac­tor­ing in essen­tial train­ing which gets out of under­stand­ing, how impor­tant it is to know refac­tor­ing at early stage.
[21:26] <Brad82> pro­gram­mer remem­ber, its de facto to use $vari­able = mysqli_escape..($_GET[’variable’]); and then use $vari­able through­out the script later on (for exam­ple in the strlen() check).
[21:26] <HAWK> There you go eip56 :) Any­way, check out our stream later on to see what peo­ple sug­gest
[21:26] <pro­gram­mer> What about input that will be returned to the user as a file?
[21:26] <Hulkur> accord­ing to php​.net you can alias classes
[21:26] <michael­sauter> Hulkur so, it would be \My\BadlyNamedNamespace as Per­fect­ly­Named­Name­space. and then PerfectlyNamedNamespace\SomeClass
[21:26] <jae­query> Mal­Cur­tis, what about Zend / PEAR way , as long as you have started your folder as ven­dor name, it won’t cause con­flicts right?
[21:26] <Brad82> pro­gram­mer that would not need any sani­tis­ing
[21:26] <HAWK> Ok peo­ple, 5 mins left. If you have a ques­tion that you haven’t asked, now is your last chance!
[21:27] <Nofel> I was read­ing php OOP and I couldn’t under­stand par­ent and what does it do
[21:27] <Brad82> par­ent refers to the class from which the cur­rent class was extended from.
[21:27] <michael­sauter> jae­query using name­space, you still start with the ven­dor name
[21:27] <Nofel> Brad82 like a exam­ple?
[21:27] <san­touras> Nofel par­ent will call the par­ent func­tion from a sub­class. which is handy if you are redefin­ing a func­tion
[21:27] <pro­gram­mer> My other ques­tion is prob­a­bly too com­pli­cated and I should prob­a­bly ask on the Site­point forum.
[21:27] <Hulkur> B extends A => par­ent is A
[21:27] <jae­query> only thing name­space solves is that it can shorten the class name
[21:28] <jae­query> which imo w/ IDE is not really that big of an issue
[21:28] <michael­sauter> jae­query basi­cally, only use libraries that fol­low psr0,1,2. then you won’t have con­flicts and good inter­op­er­abil­ity
[21:28] <Brad82> Nofel there is a great exam­ple of par­ent at http://​php​.net/​m​a​n​u​a​l​/​e​n​/​k​e​y​w​o​r​d​.​p​a​r​e​n​t​.​php
[21:28] <jae­query> and why do we have so many PSRs
[21:28] <san­touras> jae­query it is also impor­tant as Mal­Cur­tis men­tioned to help you write encap­su­lated code
[21:28] <jae­query> shouldnt we just have a “sin­gle” one?
[21:29] <Paul> Notel … yep I’m doing it now
[21:29] <jae­query> how do we stan­dard­ize it when there are so many w/ new ones being added every month
[21:29] <michael­sauter> jae­query they address dif­fer­ent issues
[21:29] <Hulkur> 0 is autoloader, 2 is code style iirc
[21:29] <Paul> Notel do it with rest­ful ser­vices and ajax or json
[21:29] <michael­sauter> See https://​github​.com/​p​h​p​-​f​i​g​/​f​i​g​-​s​t​a​n​d​a​rds
[21:29] <Nofel> Brad82 that was help­ful.
[21:30] <jae­query> ah gotcha
[21:30] <Brad82> @nor
[21:30] <jae­query> i like this chat, when is the next one and how often do you guys do it?
[21:30] <Brad82> Nofel, do you need that explain­ing any fur­ther?
[21:30] <san­touras> jae­query every week!
[21:30] <Paul> Notel do a wor­dr­pess plu­gin
[21:30] <san­touras> but not always on PHP ;)
[21:31] <Nofel> i am try­ing to learn magento and it’s all OOP so what I need php or OOP or mvc
[21:31] <HAWK> Aaaannnnddd… that’s a wrap!
[21:31] <jae­query> i’d like to see a chat for angu­lar
[21:31] <HAWK> I’m going to cut our experts free when­ever they want to go
[21:31] <HAWK> The rest of you are free to stay as long as you like
[21:31] <pro­gram­mer> Thank you so much. This was great.
[21:31] <Hulkur> @Nofel you need some­one who knows magento
[21:31] <Nofel> Brad82 why use par­ent when u can refer to the func­tion
[21:31] <HAWK> You’re in luck jae­query – there is an Angu­lar one in a cou­ple of weeks
[21:31] <san­touras> thanks HAWK :)
[21:31] <michael­sauter> Thanks for join­ing!
[21:31] <san­touras> thanks room!

The post Talk PHP with the Experts:The Tran­script appeared first on Site­Point.

Talk PHP with the Experts:The Transcript

Talk with the Experts this morn­ing was a busy one, with close to a record num­ber of atten­dees. Hardly sur­pris­ing really, con­sid­er­ing that the sub­ject was PHP. Luck­ily for me, the experts were our very own devel­op­ers Jude Aak­jaer and Michael Sauter, and they were super quick off the mark. I didn’t even have to queue the ques­tions. Too easy.

The thing that excited me the most about the chat was that we finally got to use the code win­dow that I com­mis­sioned months ago, and it was a huge suc­cess. If you read through the tran­script below, you’ll see the code saved to Gists through­out the dialogue.

The ses­sion next week is likely to be another pop­u­lar one – I’ll be talk­ing with Wave Digital’s Matt Evans about Devel­op­ing Mobile Appli­ca­tions. That ses­sion will take place at 1:30pm PDT on Wed 23 Oct and you can join the ses­sion here.

If you missed the talk this morn­ing because you didn’t know about it, make sure you sign up for email noti­fi­ca­tions of future ses­sions here.

And if you want to see what went down today, you can read the full tran­script here:

[20:28] <john­lacey> What’s the most impor­tant a begin­ner to PHP needs to know to get started?
[20:30] <san­touras> john­lacey: like learn­ing any new thing, I think its pretty impor­tant to be get­ting taught by some­one who knows what they’re doing
[20:30] <weebit> Is learn­ing PHP a good thing to do for any­one want­ing to make themes for CMS’s?
[20:31] <john­lacey> I notice a lot of people/sites rec­om­mend XAMPP for Win­dows based local devel­op­ment (includ­ing Sitepoint’s Kevin Yank). Am I miss­ing out on any­thing by using WAMP instead?
[20:31] <michael­sauter> @johnlacey I think there is noth­ing par­tic­u­lar that one needs to know to get started. PHP is one of the lan­guages that is really easy to get into and there is lots of tuto­ri­als etc. on the web. i would say that’s one of the prob­lems too: there is a lot of old/outdated/bad infor­ma­tion out there
[20:31] <michael­sauter> @weebit yes, def­i­nitely
[20:31] <michael­sauter> weebit lots of CMS are writ­ten in PHP, so know­ing some PHP to write tem­plates will be help­ful
[20:31] <san­touras> john­lacey I’d rec­om­mend using a vir­tual machine setup per­son­ally instead of xampp/wampp
[20:32] <HAWK> I’ll plug our pop­u­lar PHP course https://​learn​able​.com/​c​o​u​r​s​e​s​/​p​h​p​-​m​y​s​q​l​-​w​e​b​-​d​e​v​e​l​o​p​m​e​n​t​-​f​o​r​-​b​e​g​i​n​n​e​r​s​-13
[20:32] <san­touras> almost all deploy­ment is on linux machines and if you’re cod­ing on win­dows, it is far eas­ier to have your dev envi­ron­ment mach your pro­duc­tion envi­ron­ment
[20:33] <san­touras> if you’re cod­ing on osx/linux then dev on your local machine becomes more attrac­tive but I’d never code php directly onto win­dows again
[20:33] <bobo> hello every­body! how would you pre­vent post data being resub­mit­ted on refresh/navigation?
[20:34] <michael­sauter> same here. always bet­ter to have a portable vir­tual machine for dev around
[20:34] <evil­nick> PHP is evil!
[20:34] <Brad82> I sec­ond not cod­ing php directly on win­dows.
[20:34] <McGeough> 1) which is the most used devel­op­ment using PDO or MySQLi? and 2) Which is the best frame­work around? Codeigniter, lar­avel, zend etc
[20:35] <san­touras> @bobo this is more of a browser ques­tion :) but some strate­gies include pro­cess­ing the data on post and then for­ward­ing the user to a results page
[20:35] <HAWK> Wel­come if you just joined. Jump in with ques­tions at any time. :)
[20:35] <san­touras> @McGeough I tend to use PDO when I’m not using an abstrac­tion layer
[20:35] <evil­nick> McGeough PDO is bet­ter because it pro­vides some level of abstrac­tion, so you can use any data­base you want
[20:35] <michael­sauter> McGeough 2) depends very much on your pref­er­ence. i per­son­ally favour Symfony2
[20:35] <Brad82> McGeough 2) is a very sub­jec­tive ques­tion, some are more suit­able than oth­ers for dif­fer­ent cir­cum­stances. I’m a fan of FuelPHP per­son­ally
[20:35] <san­touras> the frame­work ques­tion is like a reli­gious argu­ment
[20:35] <evil­nick> also MySQL kinda sucks, try Post­greSQL
[20:36] <McGeough> Ive heard of Symfony2 but never got look­ing at it
[20:36] <Ick­leChris> 2) is def­i­nitely project based. It’s like try­ing to decide what size gun to use to shoot a mouse
[20:36] <weebit> So how far up the lad­der in PHP in learn­ing should I go if I am just learn­ing PHP for themes? Is there a cer­tain part of PHP I should learn?
[20:37] <san­touras> @McGeough I’ve recently been using Silex which is a trimmed down ver­sion of symfony2, def­i­nitely handy for small projects
[20:37] <michael­sauter> to fig­ure out “which frame­work should i use”, I think it’s best to look first at your require­ments, then what cod­ing style / approach you like and maybe also who you want to work with, then pick a frame­work
[20:37] <Paul> Does PDO work with mon­goDB
[20:37] <san­touras> @weebit what kind of them­ing are you refer­ring to? which plat­form specif­i­cally?
[20:37] <evil­nick> Paul of course not, PDO is for SQL
[20:37] <weebit> Word­Press and maybe Joomla later on
[20:38] <HAWK> If you just got here, hi. :) Feel free to join in with ques­tions when you’re ready
[20:38] <McGeough> Also which tem­plat­ing engines are best for PHP, so far ive been using Smarty through work and we are won­der­ing if there is any­thing bet­ter and faster?
[20:38] <michael­sauter> So Word­Press uses PHP in a very …. let’s say … inter­est­ing … way. Not too much learn to fig­ure out what’s hap­pen­ing in tem­plates
[20:39] <san­touras> McGeough I’ve been a fan of smarty in the past and used it in a lot of projects. Twig is sim­i­lar in syn­tax and is also worth look­ing at
[20:39] <michael­sauter> McGeough again, tempt­ing is also a mat­ter of pref­er­ence. I’m again in favour of Twig
[20:39] <sh4d0ws> i think that we need to think about which one will con­tinue hav­ing suport in the future… 1 or 2 year… because if we take a lot of time learn­ing and devel­op­ing some­thing and then after 2 or 3 year the frame­work is “dead”, its worth­less
[20:39] <Brad82> What advan­tages is there over using a tem­plat­ing engine over just plain old PHP in tem­plates
[20:39] <McGeough> san­touras michael­sauter is twig any faster or light­weight etc?
[20:40] <michael­sauter> In Twig you don’t have to / can’t write any PHP, but it’s still very fast as it com­piles to PHP
[20:40] <Brad82> Of course I only mean echo and fore­ach() for exam­ple in tem­plates.
[20:40] <san­touras> Brad82 the biggest advan­tage is sep­a­ra­tion of con­cern
[20:40] <evil­nick> Brad82 well, they’re not as ugly as PHP
[20:40] <john­lacey> I realise this is a very subjective/personal thing… but just out of curios­ity what’s your pre­ferred code edi­tor?
[20:40] <san­touras> it clearly defines the logic and pre­sen­ta­tional aspects of your appli­ca­tion
[20:40] <clif­fgs> Net Beans is my pre­ferred edi­tor
[20:40] <Ick­leChris> I’m an Aptana Stu­dio guy
[20:40] <san­touras> john­lacey my per­sonal is ST2, and ST3 when it becomes sta­ble, but I use vim from time to time
[20:41] <McGeough> ST2
[20:41] <Brad82> ST2 for me also
[20:41] <McGeough> ST3 just isnt sta­ble enough right now
[20:41] <sh4d0ws> any­one now how to get all par­ti­tions in nix from PHP with­out pars­ing “df” ?
[20:41] <evil­nick> Sub­lime and vim are the best
[20:41] <pro­gram­mer> My ques­tion is about secu­rity. I am con­nect­ing to a MySQL data­base, and I have the con­nec­tion con­stants in a sep­a­rate file. Should I place that file out­side the doc­u­ment root, just to be sure? And if so, how do I ref­er­ence it?
[20:41] <michael­sauter> i used to code a lot in PHP­Storm, now using Sub­lime
[20:42] <Brad82> McGeough I’ve been using ST3 for months now and it hasnt crashed on me once (touch­wood)
[20:42] <sh4d0ws> ST2 :D
[20:42] <san­touras> pro­gram­mer absolutely. If at all pos­si­ble the only code in the web root should be the boot­strap­ping index.php file and any pub­lic assets
[20:42] <san­touras> almost all mod­ern frame­works oper­ate like this
[20:43] <michael­sauter> pro­gram­mer PHP can still include that file, but there is a set­ting in php.ini which allows/denies this. I think it’s on by default
[20:43] <pro­gram­mer> I haven’t been able to find an exam­ple of this, how­ever. I am using IIS.
[20:43] <McGeough> Brad82 ive used it a few times and it did crash, maybe i just had bad luck, but will be upgrad­ing
[20:43] <san­touras> pro­gram­mer are you deploy­ing to IIS or just using that for devel­op­ment?
[20:43] <san­touras> wel­come Mal­Cur­tis :)
[20:44] <Mal­Cur­tis> Thanks! I have to say the two experts have very hand­some pro­file pics
[20:44] <amir> ST3 is good in terms of speed
[20:44] <pro­gram­mer> I’m actu­ally using apache for local devel­op­ment, but have a true devel­op­ment envi­ron­ment in IIS. Pro­duc­tion is IIS.
[20:44] <amir> but some­thing is still miss­ing
[20:44] <Brad82> I still have night­mares about using IIS at work for pro­duc­tion.
[20:44] <san­touras> Brad82 me too :( and I haven’t had to deploy to IIS in around 8 years!
[20:44] <pro­gram­mer> I’m not too crazy about IIS myself, but the project is an addi­tion to an exist­ing site, so I don’t have much choice.
[20:45] <HAWK> Yay! The code edi­tor!
[20:45] <san­touras> magic is hap­pen­ing
[20:45] <Brad82> pro­gram­mer is it IIS7 you are deploy­ing to?
[20:45] <john­lacey> I don’t think I’ve ever seen any­one use the code edi­tor in here before. lol. Excit­ing times.
[20:45] <McGeough> Slightly off topic but for those using Ver­sion Con­trol would you ever take your whole projects (all projects on sys­tem) folder as a repos­i­tory or sep­a­rate repos­i­tory for each project
[20:46] <san­touras> sep­a­rate repo
[20:46] <HAWK> I know john­lacey! I chal­lenged the guys to use it ;)
[20:46] <McGeough> whos the magi­cian using it?
[20:46] <san­touras> McGeough most of my php projects these days use com­poser so this is very nat­ural
[20:46] <san­touras> michael­sauter I believe!
[20:47] <McGeough> com­poser?
[20:47] <michael­sauter> yup that’s me
[20:47] <evil­nick> can’t edit in the code edi­tor :| how do we use it
[20:47] <michael­sauter> for­got how to write con­stants out­side a class :D
[20:47] <Brad82> evil­nick ask HAWK
[20:47] <san­touras> http://​get​com​poser​.org/
[20:47] <san­touras> basi­cally PHP’s ver­sion of bundler
[20:47] <pro­gram­mer> so rel­a­tive ../ path from where I start? I assume I have to go all the way up from wher­ever the code is.
[20:48] <michael­sauter> yea in my exam­ple your doc­u­ment root is htdocs/
[20:48] <michael­sauter> config/ is not acces­si­ble by IIS
[20:48] <evil­nick> IIS sucks
[20:48] <san­touras> the rubygems equiv­a­lent is https://​pack​ag​ist​.org/
[20:48] <san­touras> evil­nick this has been estab­lished and agreed upon
[20:49] <pro­gram­mer> I wish I didn’t have to use IIS
[20:49] <san­touras> almost all actively devel­oped php projects are avail­able on pack­ag­ist
[20:49] <pro­gram­mer> I don’t think try­ing to mix two web servers is a good idea, though.
[20:49] <san­touras> if you’re putting together a new project, you should def­i­nitely give it a look, it will make using exter­nal libraries a lot eas­ier
[20:50] <pro­gram­mer> thanks
[20:51] <michael­sauter> Saved edi­tor: https://​gist​.github​.com/​6​9​9​8​459
[20:51] <evil­nick> HAWK can I use the edi­tor?
[20:52] <HAWK> Yup evil­nick – give it a go now
[20:52] <pro­gram­mer> must run a quick errand. back later.
[20:52] <michael­sauter> com­poser really is an awe­some project. it also helps with autoload­ing, all that comes with it by default
[20:52] <san­touras> php has made enor­mous strides in the last few years. if things like com­poser and PSR-0 had been around 8 years ago it would have helped a lot
[20:53] <michael­sauter> that’s one of the things which is rel­a­tively new and which might not be men­tioned in a lot of tuto­ri­als, although it is incred­i­bly help­ful to learn after you know some PHP basics
[20:53] <san­touras> and things like boris -> https://​github​.com/​d​1​1​w​t​q​/​b​o​ris
[20:54] <san­touras> wel­come new peo­ple
[20:54] <Paul> I think grunt also fits into this pic­ture
[20:54] <michael­sauter> grunt is more for fron­tend tasks, and is run­ning on nodejs. but def­i­nitely some­thing that makes life a lot eas­ier :)
[20:56] <Ger­win> can we talk about using name­spaces?
[20:56] <san­touras> sure
[20:56] <michael­sauter> sure!
[20:56] <michael­sauter> what would inter­est you?
[20:56] <Brad82> name­spaces <3
[20:57] <Ger­win> i haven’t used them before but i really like what they do, can we go over a good use case, when and when not to use them?
[20:57] <Ger­win> any short falls etc
[20:57] <pamelasue101> I’m lis­ten­ing today, I don’t know what ques­tions to ask and I’m just learn­ing
[20:57] <eip56> Can answer mine after. But hows does every­one feel about get/set meth­ods in PHP OOP. Cre­ate gets and sets or use magic meth­ods?
[20:57] <HAWK> All good pamelasue101 :)
[20:57] <harlem> I wanted to secure this “news.php?news_id=$row[’id’]“, I heard that I could encrypt the id ? Can you some­one guide me with this ? Sorry I speak french my sen­tences will not come gra­mat­i­caly cor­rect
[20:58] <Paul> don’t classes pretty much put name­spaces to the way­side?
[20:58] <Brad82> harlem what advan­tages would you gain by encrypt­ing the ID?
[20:58] <michael­sauter> I think it’s almost always a good idea to use name­spaces, except when you just have maybe 3–4 files
[20:58] <san­touras> Paul, no not really
[20:58] <evil­nick> name­spaces is an attempt to cre­ate some­thing like Mod­ules in Ruby
[20:58] <michael­sauter> if you’re writ­ing a library or using a library you should­def­i­nitely use them
[20:58] <Ger­win> thought as much
[20:59] <Ger­win> to avoid clashes with other com­mon class names?
[20:59] <Ger­win> so
[20:59] <Ger­win> users
[20:59] <Ger­win> would be gerwins_plugin\users
[20:59] <Ger­win> some­thing like that?
[20:59] <michael­sauter> the trick­i­est is to autoload the name­spaces, but there are stan­dards which make that quite easy. so if you stick to those stan­dards you and other libraries can load the classes by default
[20:59] <michael­sauter> see for exam­ple http://​www​.site​point​.com/​a​u​t​o​l​o​a​d​i​n​g​-​a​n​d​-​t​h​e​-​p​s​r​-​0​-​s​t​a​n​d​a​rd/
[20:59] <Ger­win> awe­some
[21:00] <Ick­leChris> I hear a lot about how cre­at­ing a CMS/Framework is a great way to fur­ther develop basic PHP skills.. Is this really a good place to start, and are there any point­ers for this?
[21:00] <san­touras> eip56 I like them in the­ory because it cuts down on the num­ber of acces­sor meth­ods you need to write, but they are slower than direct func­tion calls
[21:01] <Hulkur> Ickle, i don’t rec­om­mend
[21:01] <michael­sauter> @eip56 I per­son­ally pre­fer get/set meth­ods, but they are a bit tedious to write, which is why I pre­fer PHP­Storm when I do exten­sive PHP pro­gram­ming
[21:01] <Brad82> Ick­leChris some say a blog is a good thing to cre­ate if you are new to PHP
[21:01] <michael­sauter> (or some other IDE)
[21:01] <san­touras> Ick­leChris it prob­a­bly isn’t the best idea to cre­ate a cms/framework unless you’ve had exten­sive expe­ri­ence work­ing on one in the past
[21:01] <Hulkur> if you don’t know lan­guage you are not able to use it prop­erly
[21:01] <harlem> I wanted to secure the trans­fer of that infor­ma­tion, I read some­where it can open up for dif­fer­ent attacks
[21:01] <eip56> Also in my opin­ion Ick­leChris pick up like CodeIgniter or some­thing sim­i­lar
[21:01] <michael­sauter> Ger­win yea, but you would use Camel­Case, so GerwinPlugin\Users
[21:01] <san­touras> @harlem it sounds like you’re refer­ring to SQL injec­tion?
[21:01] <Brad82> harlem would the ID be numeric or alphanu­meric?
[21:01] <eip56> it will accel­er­ate your learn­ing curve espe­cially on OOP top­ics
[21:02] <san­touras> @harlem are you using a frame­work or library? or writ­ing all of your code directly
[21:02] <Paul> I’d like to know how to reverse engi­neer word­press so I can see exactly how it works. Any input on that?
[21:02] <Brad82> @paul as a word­press user and lover myself, that is a very… inter­est­ing task
[21:02] <Ger­win> oh right that looks nicer
[21:02] <michael­sauter> Paul Word­Press is open source, so you can just read the code base
[21:02] <san­touras> @Paul https://​github​.com/​W​o​r​d​P​r​e​s​s​/​W​o​r​d​P​r​ess
[21:02] <evil­nick> is my code cor­rect?
[21:03] <michael­sauter> Paul How­ever, I wouldn’t rec­om­mend that :)
[21:03] <harlem> yes
[21:03] <Brad82> Paul learn to love the Word­Press Codex, it is extremely use­ful
[21:03] <eip56> @Paul there is really no need to reverse engi­neer it is well doc­u­mented int he codec
[21:03] <michael­sauter> Word­Press has a lot legacy code …. and is a huge and com­plex sys­tem
[21:03] <evil­nick> haven’t used PHP for a long time, and not going to
[21:03] <san­touras> hmm, I’m not see­ing the code edi­tor update
[21:03] <harlem> the id is numeric
[21:03] <michael­sauter> me nei­ther
[21:04] <HAWK> evil­nick – what code?
[21:04] <evil­nick> hmm
[21:04] <evil­nick> so it doesn’t show up?
[21:04] <eip56> Whats everyone’s favorite IDE… Ive used sev­eral but my main atm is just Pro­gram­mers notepad
[21:04] <san­touras> @harlem are you using a frame­work?
[21:04] <eip56> Id like to find a good one for my Mac
[21:04] <san­touras> eip56 ST2 is pop­u­lar
[21:04] <san­touras> michael­sauter is a fan of php­storm
[21:05] <Hulkur> what’s ST2 ?
[21:05] <HAWK> evil­nick Save it to gist using the set­tings cog and see if we can see it then
[21:05] <evil­nick> Saved edi­tor: https://​gist​.github​.com/​6​9​9​8​654
[21:05] <san­touras> sub­lime text 2
[21:05] <Hulkur> storm is good, net­beans is free
[21:05] <Brad82> harlem, in real­ity I see very lit­tle rea­son to encode the ID. You should focus more on secur­ing your scripts inter­nals so that any­thing the user sets as ID can be parsed securely.
[21:05] <harlem> I read this book PHP Mysql web devel­op­ment
[21:05] <clif­fgs> That’s what I usu­ally do. I con­nect by include_once $_SERVER[’DOCUMENT_ROOT’] . ‘/../code/admindb.inc.php’;
[21:05] <clif­fgs> And Net Beans is cross plat­form
[21:05] <HAWK> Ok, so that worked evil­nick – not sure why we’re not see­ing it live
[21:06] <Hulkur> net­beans is java, so it eats mem­ory
[21:06] <harlem> san­touras I am not using any frame­work
[21:06] <san­touras> harlem the most impor­tant thing is sani­ti­sa­tion of any user input
[21:06] <michael­sauter> Hulkur I think almost all IDEs are Java :(
[21:06] <Brad82> harlem Remem­ber, even if in your app you encode the query string, I can always type into the address bar man­u­ally an exploit, in this case encod­ing it has no effect
[21:06] <Oliv­er­Thomas> Is there any use­ful PHP plu­g­ins for Notepad++?
[21:06] <san­touras> unless you’ve ver­i­fied it, don’t trust it
[21:07] <clif­fgs> Hulkar mem­ory is cheap and plen­ti­ful
[21:07] <san­touras> use a regex to ensure/strip out, any­thing that is not what you’re expect­ing. and if you get funny results, don’t go fur­ther
[21:07] <michael­sauter> Oliv­er­Thomas not sure, i have never used it.
[21:07] <harlem> Brad82 what can I do than I am using a php regex script to make what I $_GET is what I want
[21:08] <Oliv­er­Thomas> Hi michael, i see. what pro­gram do you rec­om­mend for PHP devel­op­ment?
[21:08] <michael­sauter> Give sub­lime text a try, it has lots of plu­g­ins
[21:08] <Hulkur> Mem­ory is plen­ty­ful, but NB still eats it all
[21:08] <Hulkur> and is slow
[21:08] <evil­nick> yea :D
[21:08] <Paul> I don’t know what it’s writ­ten in, but aptana eats mem­ory too
[21:08] <evil­nick> Aptana is Eclipse
[21:08] <Hulkur> storm some­how is faster and less hun­gry
[21:08] <san­touras> aptana is java
[21:08] <Brad82> harlem, you said the ID will be numeric? In that case all you require is to do is_numeric() on the $_GET vari­able, no slow regex required!
[21:08] <Oliv­er­Thomas> Thank you i will check it out
[21:08] <Michael> I use UltraEdit Stu­dio for PHP dev
[21:09] <san­touras> if your sen­tence is “[edi­tor] eats mem­ory” it’s most likely java based ;)
[21:09] <Hulkur> does sub­lime sup­port nav­i­gat­ing to class/function ?
[21:09] <Aaron> I like PHP­Storm
[21:09] <san­touras> yes
[21:09] <san­touras> Hulkur yes
[21:09] <michael­sauter> Yup, so that’s why PHP­Storm was/is my choice, it seemed to be the fastest amongst the heav­ier IDEs. But nowhere near ST or Text­mate etc.
[21:09] <Brad82> hawk can I get edi­tor for a sec?
[21:09] <harlem> Brad82 san­touras
[21:09] <HAWK> It doesn’t seem to be work­ing prop­erly
[21:09] <Oliv­er­Thomas> michael­sauter is it dan­ger­ous to loop through $_POST super­global when pro­cess­ing form data
[21:09] <san­touras> http://​www​.sub​lime​text​.com/ <- go to any­thing
[21:09] <Ger­win> I’m guess­ing most peo­ple here use php­MyAd­min? That right?
[21:10] <harlem> thank you guys Brad82 san­touras any links ?
[21:10] <HAWK> Give it a go now Brad82
[21:10] <michael­sauter> Oliv­er­Thomas not unless you’re doing some­thing with that data like enter­ing it into the data­base
[21:10] <Paul> I just started using vim. it’s pretty pow­er­ful
[21:10] <evil­nick> What the hell am I even doing here, I just remem­bered that I hate PHP :D
[21:10] <michael­sauter> Oliv­er­Thomas what do you want to achieve?
[21:10] <san­touras> Ger­win no, I used SQLYog on windows/linux, and Sequel­Pro on mac
[21:10] <san­touras> I’m aller­gic to php­myad­min :)
[21:10] <Oliv­er­Thomas> I use pre­pared state­ments to insert
[21:10] <Aaron> What’s the best way to ana­lyze code for secu­rity issues? I don’t have the money for Acunetix, are there any other options?
[21:10] <Ger­win> Cool, if any­one is inter­ested, i recently built this http://​cabindb​.com/
[21:11] <Oliv­er­Thomas> just seek­ing advice on the best way to do cer­tain things
[21:11] <Hulkur> new php­myad­min tree is awful
[21:11] <Ger­win> yeah
[21:11] <michael­sauter> Ger­win looks nice!
[21:11] <san­touras> Ger­win nice, very nice, will look at that
[21:11] <Michael> I use Nav­i­cat
[21:11] <san­touras> I almost always pre­fer desk­top apps, but will give that a look
[21:11] <Ger­win> thanks, it’s pretty young and i’d love for peo­ple to try it out, but don’t rely on it yet :)
[21:12] <michael­sauter> Oliv­er­Thomas so your loop­ing over $_POST, and inside the loop using pre­pared state­ments?
[21:12] <Brad82> harlem, check edi­tor as sim­ple as that!
[21:12] <Hulkur> there is some­thing bet­ter than PHP ?
[21:12] <Hulkur> can’t pos­si­bly be
[21:12] <Mal­Cur­tis> Looks good Ger­win (and Hi!)
[21:12] <jae­query> peo­ple still learn PHP?
[21:12] <michael­sauter> Oliv­er­Thomas I’d be very cau­tios even then, maybe bet­ter to just loop over keys you define, and then look up the super­global value from there
[21:13] <Brad82> harlem https://​gist​.github​.com/​6​9​9​8​745
[21:13] <eip56> jae­query you blas­phe­mer
[21:13] <eip56> PHP rocks
[21:13] <Oliv­er­Thomas> michael­sauter no no, I am pro­cess­ing the form data using a fore­ach() to trim the data and then go through each field indi­vid­u­ally check­ing for the var­i­ous require­ments, then includ­ing a pre­pared sta­tee­ment script.
[21:13] <evil­nick> thou shalt use Ruby
[21:13] * evil­nick com­mences the holy war
[21:13] <Ger­win> ruby syn­tax may induce vom­it­ing
[21:13] <san­touras> Aaron have you looked at PHPMD?
[21:13] <jae­query> it was a seri­ous ques­tion :x
[21:13] <san­touras> Ger­win evil­nick there is room in the world for many lan­guages :)
[21:14] <Hulkur> ruby syn­tax does induce vom­it­ing
[21:14] <evil­nick> not for PHP
[21:14] <san­touras> some peo­ple still use cobal
[21:14] <michael­sauter> jae­query I think PHP is not a bad choice. It’s easy to get into, and depend­ing where you live, lots of jobs. Sure other lan­guages have a bet­ter design, but there are lots of apps writ­ten in PHP
[21:14] <Aaron> san­touras I haven’t…
[21:14] <michael­sauter> Oliv­er­Thomas sounds good then
[21:14] <evil­nick> PHP doesn’t even have a nam­ing con­ven­tion
[21:14] <Ger­win> Mal­Cur­tis hey man, saw your name. Yeah it’s a start, with lim­ited amount of spare time I have haha.
[21:14] <jae­query> my php codes are good. i just can’t stand the oth­ers (word­press, dru­pal, joomla, yuck)
[21:14] <Hulkur> evil­nick, you mean not forced upon you nam­ing con­ven­tion
[21:14] <Paul> I havn’t fig­ured out and easy way how to paste code from an out­side file into vim yet other than some long com­mand in a macro
[21:15] <evil­nick> I mean core library nam­ing con­ven­tion
[21:15] <michael­sauter> evil­nick https://​github​.com/​p​h​p​-​f​i​g​/​f​i​g​-​s​t​a​n​d​a​r​d​s​/​b​l​o​b​/​m​a​s​t​e​r​/​a​c​c​e​p​t​e​d​/​P​S​R​-​2​-​c​o​d​i​n​g​-​s​t​y​l​e​-​g​u​i​d​e​.md
[21:15] <Paul> I wish I could in vim
[21:15] <Mal­Cur­tis> Ger­win can you run arbi­trary SQL queries? That’s one of my main uses for any sql tool
[21:15] <Elie> nam­ing con­ven­tion? lol use your own
[21:15] <michael­sauter> PHP has changed in the past few years
[21:15] <Ger­win> Mal­Cur­tis Yes sir, with syn­tax high­light­ing!
[21:15] <Oliv­er­Thomas> Thanks michael for the feed­back
[21:15] <Mal­Cur­tis> sheeet son.
[21:15] <Hulkur> about name­spaces, there is really not use if yoou name your classes some­thing like My_Package_Class
[21:15] <jae­query> hon­estly, i think it has turned for the worst
[21:15] <evil­nick> yeah but it’s no way to deter­mine which func­tion to use because they use dif­fer­rent nam­ing con­ven­tions
[21:15] <Ger­win> And user per­mis­sions are easy to do!
[21:15] <Hulkur> then there is no con­flict
[21:16] <harlem> thanks Brad82
[21:16] <san­touras> Hulkur I would dis­agree, mainly due to code beauty :)
[21:16] <Mal­Cur­tis> Hulkur yea that’s great until you see some big ones
[21:16] <jae­query> the autoloader dis­cus­sion on php-fig sick­ens me
[21:16] <Hulkur> i work on magento, big enough
[21:16] <Ger­win> DL it and try get it going locally, have a play. I haven’t tested on too many machines yet, mac and pc works and my AWS machine too. Still needs more test­ing, all js one page styles
[21:16] * evil­nick rage­quits
[21:16] <HAWK> evil­nick has just rage­quit
[21:17] <Mal­Cur­tis> Like: Sitepoint_Courses_PageController_CourseAdminController
[21:17] <michael­sauter> haha :)
[21:17] <eip56> HAWK this one you prob­a­bly know best but any­one else as well. A lit­tle more gen­eral can any­one rec­om­mend a ser­vice for check­ing cross browser com­pat­i­bil­ity. Hope­fully free but I know there are a few ser­vices where I can check my site in older virtual-ized browsers
[21:17] <san­touras> Mal­Cur­tis :(
[21:17] <Mal­Cur­tis> * insert vomit emoti­con here *
[21:17] <jae­query> what is this cha­t­room made in?
[21:17] <Hulkur> how it’s shorter with name­space ?
[21:17] <Brad82> Mal­Cur­tis I just had a mini stroke look­ing at that
[21:17] <jae­query> is it open­source?
[21:17] <Mal­Cur­tis> when you’re inside a name­space you don’t need to type the whole thing…
[21:17] <pro­gram­mer> Are there any other rec­om­mended checks for get and post vari­ables? I see some­thing in the code win­dow.
[21:17] <michael­sauter> Hulkur you can import name­spaces, and then just use the class name
[21:18] <Mal­Cur­tis> jae­query kinda, I started with kiwi­irc, which is an open source node.js irc client, then added in a bucket load of cus­tomiza­tions
[21:18] <Hulkur> can you show me some cor­rectly made name­spaces
[21:18] <Brad82> pro­gram­mer that was a very sim­pli­fied exam­ple to check if a get var was numeric
[21:18] <michael­sauter> pro­gram­mer so either you’re using a frame­work that does all that for you, or the best is to know what you’re using a vari­able for, and then san­i­tiz­ing it specif­i­cally for that
[21:18] <Hulkur> i think i don’t under­stand them prop­erly yet
[21:19] <san­touras> Saved edi­tor: https://​gist​.github​.com/​6​9​9​8​820
[21:19] <Brad82> pro­gram­mer it depends what you are doing with said vari­able on how you sanitise/verify it
[21:19] <HAWK> Can any­one help out eip56 with good browser com­pat­i­bil­ity test­ing ser­vices?
[21:19] <Hulkur> this is small, how do you place mod­els and views ?
[21:19] <pro­gram­mer> What is the best way to san­i­tize, then? Mostly I have strings.
[21:19] <Hulkur> you still need long names
[21:20] <Hulkur> just / instead of _
[21:20] <Brad82> @hulker
[21:20] <jae­query> is it more rec­om­mended to do Site­point or \Site­point
[21:20] <pro­gram­mer> And most of those should be only a sin­gle char­ac­ter Y or N
[21:20] <michael­sauter> @programmer depends where you want to use that string. when you want to dis­play it, use html­spe­cialchars or sim­i­lar, when for mysql, use some mysql escape func­tion
[21:20] <san­touras> jae­query gen­er­ally you would use Site­point unless you wanted to ensure you hit the root level
[21:21] <pro­gram­mer> OK, I think I’ve got mysqli_real_escape or some­thing like that.
[21:21] <san­touras> jae­query you see this most often with peo­ple explic­itly using the \Excep­tion class
[21:21] <pro­gram­mer> Because they go into a db query
[21:21] <Paul> elp56 I like http://​quirk​tools​.com/​s​c​r​e​e​n​f​ly/
[21:21] <jae­query> why wouldnt you always want to start from root?
[21:21] <Paul> but that’s screen res­o­lu­tion
[21:21] <HAWK> eip56 Are you on Twit­ter? I’ve just tweeted your ques­tion from @sitepointdotcom
[21:22] <michael­sauter> Hulkur see my exten­sion of the code. you can use the short names once you import a name­space at the top of the file
[21:22] <san­touras> jae­query because it resolves to any imported name­spaces
[21:22] <michael­sauter> pro­gram­mer yea that’s good if you use it inside a sql query
[21:22] <AlexF> Another nice ben­e­fit of name­spaces is alias­ing use Some\Other\Namespace as NS;
[21:22] <san­touras> so start­ing from root kind of takes away the whole point of “use”
[21:22] <jae­query> how does name­space han­dle things where you have Site­point\* , and some­one else also has Site­point\* out of sheer luck?
[21:23] <Nofel> i had been fan of php since many years but how can I apply, u can’t get project with­out prov­ing ur a php expert so how u prac­tice a php project to test skills
[21:23] <Brad82> pro­gram­mer run­ning $_REQUEST vari­ables through mysqli_real_escape… is enough before you put it in a SQL query
[21:23] <san­touras> Nofel best thing is to write an appli­ca­tion as a per­sonal project and host the code on github
[21:23] <Paul> elp56 this is free cross­browser http://​browser​shots​.org/
[21:24] <pro­gram­mer> Excel­lent. I also am check­ing length of input.
[21:24] <eip56> HAWK I am 
[21:24] <Hulkur> thou shalt read man­ual ! :) found my miss­ing knowl­edeg use My\Full\Classname as Another;
[21:24] <eip56> :-( and i thought we were friends!
[21:24] <Nofel> san­touras u mean make ur own project?
[21:24] <michael­sauter> jae­query that’s a prob­lem then. how­ever, if you fol­low stan­dards and upload your library to pack​ag​ist​.org, that shouldn’t hap­pen
[21:24] <Hulkur> name­space alias­ing and no long names any­more
[21:24] <Nofel> what is
[21:24] <san­touras> jae­query the doc­u­men­ta­tion cov­ers res­o­lu­tion – http://​php​.net/​m​a​n​u​a​l​/​e​n​/​l​a​n​g​u​a​g​e​.​n​a​m​e​s​p​a​c​e​s​.​r​u​l​e​s​.​php
[21:24] <Brad82> pro­gram­mer first run all the vari­ables through your mysql_escape… and then use those cleaned vari­ables in strlen($var) checks after­wards
[21:24] <jae­query> thats why im con­fused , isnt the puprose of name­space to avoid col­li­sion when there is one?
[21:25] <Mal­Cur­tis> The pur­pose is to pro­vide an encap­su­lated and insu­lated place to write a pack­age of code, which hap­pens to avoid col­li­sions as a part of it
[21:25] <michael­sauter> Hulkur afaik this only aliases the name­space, not the class
[21:25] <Hulkur> yes, but then you use alias as short name­space
[21:26] <san­touras> Nofel yes, writ­ing your own project as a sam­ple appli­ca­tion
[21:26] <Nofel> I fol­low the php train­ing by Kevin skoug­land on Lynda. He do refac­tor­ing in essen­tial train­ing which gets out of under­stand­ing, how impor­tant it is to know refac­tor­ing at early stage.
[21:26] <Brad82> pro­gram­mer remem­ber, its de facto to use $vari­able = mysqli_escape..($_GET[’variable’]); and then use $vari­able through­out the script later on (for exam­ple in the strlen() check).
[21:26] <HAWK> There you go eip56 :) Any­way, check out our stream later on to see what peo­ple sug­gest
[21:26] <pro­gram­mer> What about input that will be returned to the user as a file?
[21:26] <Hulkur> accord­ing to php​.net you can alias classes
[21:26] <michael­sauter> Hulkur so, it would be \My\BadlyNamedNamespace as Per­fect­ly­Named­Name­space. and then PerfectlyNamedNamespace\SomeClass
[21:26] <jae­query> Mal­Cur­tis, what about Zend / PEAR way , as long as you have started your folder as ven­dor name, it won’t cause con­flicts right?
[21:26] <Brad82> pro­gram­mer that would not need any sani­tis­ing
[21:26] <HAWK> Ok peo­ple, 5 mins left. If you have a ques­tion that you haven’t asked, now is your last chance!
[21:27] <Nofel> I was read­ing php OOP and I couldn’t under­stand par­ent and what does it do
[21:27] <Brad82> par­ent refers to the class from which the cur­rent class was extended from.
[21:27] <michael­sauter> jae­query using name­space, you still start with the ven­dor name
[21:27] <Nofel> Brad82 like a exam­ple?
[21:27] <san­touras> Nofel par­ent will call the par­ent func­tion from a sub­class. which is handy if you are redefin­ing a func­tion
[21:27] <pro­gram­mer> My other ques­tion is prob­a­bly too com­pli­cated and I should prob­a­bly ask on the Site­point forum.
[21:27] <Hulkur> B extends A => par­ent is A
[21:27] <jae­query> only thing name­space solves is that it can shorten the class name
[21:28] <jae­query> which imo w/ IDE is not really that big of an issue
[21:28] <michael­sauter> jae­query basi­cally, only use libraries that fol­low psr0,1,2. then you won’t have con­flicts and good inter­op­er­abil­ity
[21:28] <Brad82> Nofel there is a great exam­ple of par­ent at http://​php​.net/​m​a​n​u​a​l​/​e​n​/​k​e​y​w​o​r​d​.​p​a​r​e​n​t​.​php
[21:28] <jae­query> and why do we have so many PSRs
[21:28] <san­touras> jae­query it is also impor­tant as Mal­Cur­tis men­tioned to help you write encap­su­lated code
[21:28] <jae­query> shouldnt we just have a “sin­gle” one?
[21:29] <Paul> Notel … yep I’m doing it now
[21:29] <jae­query> how do we stan­dard­ize it when there are so many w/ new ones being added every month
[21:29] <michael­sauter> jae­query they address dif­fer­ent issues
[21:29] <Hulkur> 0 is autoloader, 2 is code style iirc
[21:29] <Paul> Notel do it with rest­ful ser­vices and ajax or json
[21:29] <michael­sauter> See https://​github​.com/​p​h​p​-​f​i​g​/​f​i​g​-​s​t​a​n​d​a​rds
[21:29] <Nofel> Brad82 that was help­ful.
[21:30] <jae­query> ah gotcha
[21:30] <Brad82> @nor
[21:30] <jae­query> i like this chat, when is the next one and how often do you guys do it?
[21:30] <Brad82> Nofel, do you need that explain­ing any fur­ther?
[21:30] <san­touras> jae­query every week!
[21:30] <Paul> Notel do a wor­dr­pess plu­gin
[21:30] <san­touras> but not always on PHP ;)
[21:31] <Nofel> i am try­ing to learn magento and it’s all OOP so what I need php or OOP or mvc
[21:31] <HAWK> Aaaannnnddd… that’s a wrap!
[21:31] <jae­query> i’d like to see a chat for angu­lar
[21:31] <HAWK> I’m going to cut our experts free when­ever they want to go
[21:31] <HAWK> The rest of you are free to stay as long as you like
[21:31] <pro­gram­mer> Thank you so much. This was great.
[21:31] <Hulkur> @Nofel you need some­one who knows magento
[21:31] <Nofel> Brad82 why use par­ent when u can refer to the func­tion
[21:31] <HAWK> You’re in luck jae­query – there is an Angu­lar one in a cou­ple of weeks
[21:31] <san­touras> thanks HAWK :)
[21:31] <michael­sauter> Thanks for join­ing!
[21:31] <san­touras> thanks room!

The post Talk PHP with the Experts:The Tran­script appeared first on Site­Point.