Tagged: php

Finally managed to unpack everything after moving flats so no more boxes, yey! Unfortunately somehow managed to lose the box with my socks and underwear tho. Oh well, you win some you lose some. Anyway, had some time today to work on this app of mine.

First of all I wanted to pretty it up a little bit. I have no sense of style at all (don’t think any coder does) but I do not like working with anything too messy. So here are a couple of things I did to make me feel more comfortable:

I’ve reordered my tabs in my TabBarController to make the “Play” item to be in the center. For much of my surprise the storyboard editor doesn’t let me select the default tab. I realized that I have to extend the TabBarController. So after much research I found a code snippet that did the trick

I’ve also made the tab bar’s color scheme inverse so the above code takes care of the font colors as well. I also wanted to display a heading on all pages with a title so dragged in a Navigation Controller and connected it to my Tab Bar Controller. It displayed the heading placeholder but I couldn’t find a way in the storyboard editor to set the text for each tab element. Clever people of stack overflow said that i can set the title from the ViewDidAppear method of each controller. Here is an example of how:

Swift

1

2

3

4

5

overridefuncviewDidAppear(animated:Bool){

super.viewDidAppear(animated)

self.tabBarController?.title="Play BillionQuestions"

}

Since I really don’t like the UIColor API (coming from web development background I think it’s understandable) I was looking for an easy to use alternative. Thats how i found UIColorExtension. Its a simple extension that allows me to use RGB(a) hex codes in my color definitions. So I can write stuff like this:

Swift

1

UITabBar.appearance().tintColor=UIColor(rgba:"#ffffff")

Winning (except for the 15 minutes it took me how to do # on a mac keyboard)

Also replaced my label that was used for the countdown with a Progress View. Progress View’s are really straight forward to use:

All right. I think I’m done with prettying stuff up. It is still ugly as fuck but bit easier on the eye:

I hooked it up with the question API I made in my previous post and it worked like a charm. Except one thing: Since the API was using random sometimes it gave me the same question twice. In order to avoid that I needed to log the user’s answers. So created a new table:

PgSQL

1

2

3

4

5

6

7

8

9

10

11

12

CREATETABLE`user_answers`(

`id`int(11)NOT NULLAUTO_INCREMENT,

`user_id`int(11)NOT NULL,

`question_id`int(11)NOT NULL,

`answer`tinyint(4)NOT NULL,

`correct`tinyint(4)NOT NULL,

PRIMARYKEY(`id`),

KEY`user_id`(`user_id`),

KEY`question_id`(`question_id`),

KEY`answer`(`answer`),

KEY`correct`(`correct`)

)DEFAULTCHARSET=utf8

And a new class:

PHP

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

classAnswerextendsModel{

public$db=null;

public$schema=array("id"=>array("type"=>"int",

"unique"=>true,

"notnull"=>true,

"nice_name"=>"Id"),

"question_id"=>array("type"=>"int",

"unique"=>false,

"required"=>true,

"notnull"=>true,

"nice_name"=>"QuestionId"),

"user_id"=>array("type"=>"int",

"required"=>true,

"notnull"=>true,

"nice_name"=>"UserId"),

"answer"=>array("type"=>"int",

"required"=>true,

"nice_name"=>"Answer"),

"correct"=>array("type"=>"int",

"required"=>true,

"nice_name"=>"Correct")

);

public$table="user_answers";

public$nice_name="Answer";

function__construct($db){

global$baseurl,$basepath;

$this->db=$db;

}

}

The PHP API has been modified a little as well to able to record answers + avoid sending the same question to the same user again:

PHP

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

publicfunctiongetUserQuestions($user_id){

$questions=array();

$res=$this->answer_api->get(array("user_id"=>$user_id),0);

foreach($resas$row_id=>$row){

$questions[]=$row['question_id'];

}

return$questions;

}

publicfunctionanswer(){

$errors=$this->answer_api->validate($this->params);

if(!empty($errors)){

$this->raiseError(json_encode($errors));

}

$this->answer_api->add($this->params);

}

publicfunctionquestion(){

if(!isset($this->params['user_id'])||!$this->params['user_id']){

$this->raiseError("missing param: user_id");

}

$question_ids=$this->getUserQuestions($this->params['user_id']);

if(empty($question_ids)){

$query="SELECT * FROM questions ORDER BY rand() LIMIT 1";

}else{

$query="SELECT * FROM questions WHERE id NOT IN (".implode(",",$question_ids).") ORDER BY rand() LIMIT 1";

}

$res=$this->db->query($query)ordie($this->db->error." on line #".__LINE__);

if($res->num_rows){

$row=$res->fetch_assoc();

$ret=array();

$ret['id']=(int)$row['id'];

$ret['question']=$row['question'];

$ret['category']=$row['category'];

$ret['correct']=(int)$row['correct_answer'];

$ret['current_post']=100000000;// TODO

$ret['answers']=array(

$row['answer1'],

$row['answer2'],

$row['answer3'],

$row['answer4']

);

print(json_encode($ret));

}

}

Great, now the only thing left to do is to make the app send home the user’s answer for logging. In my PlayViewController I modified the logic that happens when the user clicks one of the answer buttons:

When the user hits the button it just checks against self.currentCorrectAnswer and depending on the result it sends home the questionId, userId and 0 or 1 for logging.

Finally I decided to make this project fully open source. Please feel free to fork / do a pull request / whatever, but keep in mind it is very much a work in progress and I have literally no idea what am I doing in Swift

The game is actually playable now and it is moderately entertaining. Will need to find a new source of questions because the current ones are way too British.

What is next? The gameplay is pretty much ready now. It needs some refactoring and some security on the API but its ok for now. Next time I’m going to work on the leaderboard view. Deal with some TableViews in xcode and probably implement Facebook friend list somehow.

Ok, I’m cheating a little bit here. I did not work on the app during the past two weeks or so but I have very good reasons. First of all I moved to a new flat (which I absolutely love btw) and as you know moving is hard. Secondly the Macbook I borrowed from work pretty much died under me. It kept presenting the so called “black screen of death” 9 out of 10 times I tried to boot. Tried to do all the PRAM resets and mental keyboard combos I could find online but no joy. Anyway, bought the new generation Macbook Pro now (force touch trackpad rulez btw) so I’m back in business.

That being said yesterday I only worked on the back-end of the app. In order to go forward with the actual iOS development I needed some questions and answers in my database so I decided to look around to find a site which I can scrape. I’m really surprised that there are no good quiz sites around with 4 answers for each question and the correct answer included. Found some databases for sale that would fit my needs but the sales page were either crappy or the database was ridiculously overpriced. The only site I could find that met all my requirements is PubQuizArea, which ticks all the boxes, however it is really British. Oh well, it should do for now.

First of all I need a table structure:

PgSQL

1

2

3

4

5

6

7

8

9

10

11

CREATETABLE`questions`(

`id`int(11)NOT NULLAUTO_INCREMENT,

`question`varchar(500)COLLATEutf8_binNOT NULL,

`answer1`varchar(200)COLLATEutf8_binNOT NULL,

`answer2`varchar(200)COLLATEutf8_binNOT NULL,

`answer3`varchar(200)COLLATEutf8_binNOT NULL,

`answer4`varchar(200)COLLATEutf8_binNOT NULL,

`correct_answer`tinyint(4)NOT NULL,

`category`varchar(200)COLLATEutf8_binDEFAULTNULL,

PRIMARYKEY(`id`)

)ENGINE=InnoDBDEFAULTCHARSET=utf8COLLATE=utf8_bin

The model for this is written with my No-BS Framework. It does not need to modify the base model at all, just need to define the table fields and some validation rules (question needs to be unique:

PHP

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

<?php

classQuestionextendsModel{

public$db=null;

public$schema=array("id"=>array("type"=>"int",

"unique"=>true,

"notnull"=>true,

"nice_name"=>"Id"),

"question"=>array("type"=>"string",

"unique"=>true,

"required"=>true,

"notnull"=>true,

"nice_name"=>"Question"),

"answer1"=>array("type"=>"string",

"required"=>true,

"notnull"=>true,

"nice_name"=>"Answer1"),

"answer2"=>array("type"=>"string",

"required"=>true,

"notnull"=>true,

"nice_name"=>"Answer2"),

"answer3"=>array("type"=>"string",

"required"=>true,

"notnull"=>true,

"nice_name"=>"Answer3"),

"answer4"=>array("type"=>"string",

"required"=>true,

"notnull"=>true,

"nice_name"=>"Answer4"),

"correct_answer"=>array("type"=>"int",

"required"=>true,

"notnull"=>true,

"nice_name"=>"Correct answer"),

"category"=>array("type"=>"string",

"required"=>true,

"notnull"=>false,

"nice_name"=>"Category"),

);

public$table="questions";

public$nice_name="Question";

function__construct($db){

global$baseurl,$basepath;

$this->db=$db;

}

}

The main part of the job is writing a simple scraper. Luckily the site’s structure is pretty well thought out so it makes it easy to scrape:

I know I know. Heard it million times: my scraping style is really old school. Guess what? I tried all those hipster libraries for scraping which promise you bells and whistles, none of those worked for me. Every once in a while they stop working and it is really hard to find the actual issue under the hood. As always I’m using my trusty curl class to fetch the data.

The script is just looping through the subpages of the category url from the command line argument and get the question / answer data from them. Luckily the correct answer is highlighted with a separate class (“blue”) so it is easy to recognize. $question->validate($db_data); takes care of removing dupes too.

That site gave me about ~1,800 questions. Obviously not enough, but will do for testing.

Last thing was to add an endpoint to my api. My __construct became:

PHP

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

function__construct($db,$params){

$this->db=$db;

$this->user=newUser($this->db);

$this->question_api=newQuestion($this->db);

$this->params=$params;

if(!isset($params['method'])){

$this->raiseError("No method provided");

}

if($this->params['method']=="register"){

$this->register();

}elseif($this->params['method']=="login"){

$this->login();

}elseif($this->params['method']=="question"){

$this->question();

}elseif($this->params['method']=="facebookLogin"){

$this->facebookLogin();

}elseif($this->params['method']=="stub"){

$this->stub();

}else{

$this->raiseError("unknown method: {$this->params['method']}");

}

}

And the implementation is:

PHP

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

publicfunctionquestion(){

$res=$this->db->query("SELECT * FROM questions ORDER BY rand() LIMIT 1")ordie($this->db->error." on line #".__LINE__);

if($res->num_rows){

$row=$res->fetch_assoc();

$ret=array();

$ret['id']=$row['id'];

$ret['question']=$row['question'];

$ret['category']=$row['category'];

$ret['correct']=$row['correct_answer'];

$ret['current_post']=100000000;// TODO

$ret['answers']=array(

$row['answer1'],

$row['answer2'],

$row['answer3'],

$row['answer4']

);

print(json_encode($ret));

}

}

Obviously this logic will change as I hook it up with the app (rand() doesn’t exactly prevents the user from getting the same question over and over again) but again, its ok for testing. If you fancy trying it out, click here

Read this article today on HN about 5 alternatives for fizzbuzz for coding interviews. The last one was to write the worst fizzbuzz program you can come up with. It sounded like something i should do before my morning coffee so here is my entry:

PHP

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

$limit=100;

$prog='$cntr = 1;'."\n";

$prog.='while($cntr <= '.$limit.'){'."\n";

$prog.=' switch($cntr){'."\n";

for($i=1;$i<=$limit;$i++){

if($i%3==0&amp;&amp;$i%5==0){

$prog.=" case $i:\n print(\"fizzbuzz \"); break;\n";

}elseif($i%3==0){

$prog.=" case $i:\n print(\"fizz \"); break;\n";

}elseif($i%5==0){

$prog.=" case $i:\n print(\"buzz \"); break;\n";

}else{

$prog.=" case $i:\n print(\"$i \"); break;\n";

}

}

$prog.=' }'."\n";

$prog.=' $cntr++;'."\n";

$prog.='}'."\n";

eval($prog);

Can you do worse?

PS: No movement on my iPhone app today since I decided to get drunk yesterday

Task 1: Beautiful strings

When John was a little kid he didn’t have much to do. There was no internet, no Facebook, and no programs to hack on. So he did the only thing he could… he evaluated the beauty of strings in a quest to discover the most beautiful string in the world.

Given a string s, little Johnny defined the beauty of the string as the sum of the beauty of the letters in it.

The beauty of each letter is an integer between 1 and 26, inclusive, and no two letters have the same beauty. Johnny doesn’t care about whether letters are uppercase or lowercase, so that doesn’t affect the beauty of a letter. (Uppercase ‘F’ is exactly as beautiful as lowercase ‘f’, for example.)

You’re a student writing a report on the youth of this famous hacker. You found the string that Johnny considered most beautiful. What is the maximum possible beauty of this string?

Input
The input file consists of a single integer m followed by m lines.

Output
Your output should consist of, for each test case, a line containing the string “Case #x: y” where x is the case number (with 1 being the first case in the input file, 2 being the second, etc.) and y is the maximum beauty for that test case.

Constraints
5 ≤ m ≤ 50
2 ≤ length of s ≤ 500

My solution for this problem was fairly straight forward. Not the fastest solution I guess, but it works: get the string, count the unique alpha characters in it and add up the “beauty”

PHP

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

<?php

$content=file_get_contents("input.txt");

$content=preg_replace("/\r\n/i","\n",$content);

$rows=explode("\n",$content);

$row_count=$rows[0];

if(!is_numeric($row_count)){

print("invalid input\n");

exit();

}

$handle=fopen("output.txt","w+");

for($case=1;$case<=$row_count;$case++){

$row=$rows[$case];

$row=strtolower(preg_replace("/[^a-zA-Z]/i","",$row));

if(!strlen($row)){

print("Case #$case: 0\n");

fwrite($handle,"Case #$case: 0\n");

continue;

}

$letters=array();

for($j=0;$j<strlen($row);$j++){

if(!isset($letters[$row[$j]])){

$letters[$row[$j]]=1;

}else{

$letters[$row[$j]]++;

}

}

$total_beauty=0;

$current_beauty=26;

arsort($letters);

foreach($lettersas$letter=>$count){

$total_beauty+=$count*$current_beauty;

$current_beauty--;

}

print("Case #$case: $total_beauty\n");

fwrite($handle,"Case #$case: $total_beauty\n");

}

Task 2: Balanced Smileys

Your friend John uses a lot of emoticons when you talk to him on Messenger. In addition to being a person who likes to express himself through emoticons, he hates unbalanced parenthesis so much that it makes him go

Sometimes he puts emoticons within parentheses, and you find it hard to tell if a parenthesis really is a parenthesis or part of an emoticon.

A message has balanced parentheses if it consists of one of the following:
– An empty string “”
– One or more of the following characters: ‘a’ to ‘z’, ‘ ‘ (a space) or ‘:’ (a colon)
– An open parenthesis ‘(‘, followed by a message with balanced parentheses, followed by a close parenthesis ‘)’.
– A message with balanced parentheses followed by another message with balanced parentheses.
– A smiley face “:)” or a frowny face “:(”

Write a program that determines if there is a way to interpret his message while leaving the parentheses balanced.
Input

The first line of the input contains a number T (1 ≤ T ≤ 50), the number of test cases.
The following T lines each contain a message of length s that you got from John.
Output

For each of the test cases numbered in order from 1 to T, output “Case #i: ” followed by a string stating whether or not it is possible that the message had balanced parentheses. If it is, the string should be “YES”, else it should be “NO” (all quotes for clarity only)
Constraints
1 ≤ length of s ≤ 100

I spent quite a lot of time, about 40 minutes on this one. I ended up with a recursive function which relies on a regular expression: “/(\(.*)(:\))?(:\()?(\))/U”. This regex will match the parts of the string which are in brackets even if the parts are containing a smiley. Then it is just a loop for counting the opening and closing parentheses.

PHP

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

<?php

$content=file_get_contents("input.txt");

$content=preg_replace("/\r\n/i","\n",$content);

$rows=explode("\n",$content);

$row_count=$rows[0];

if(!is_numeric($row_count)){

print("invalid input\n");

exit();

}

functionreplace_once($haystack,$needle,$replacement){

$pos=strpos($haystack,$needle);

if($pos!==false){

returnsubstr_replace($haystack,$replacement,$pos,strlen($needle));

}else{

return$haystack;

}

}

functionis_balanced($string){

preg_match_all("/(\(.*)(:\))?(:\()?(\))/U",$string,$matches);

if(count($matches)&&count($matches[0])){

$remaining=$string;

foreach($matches[0]as$key=>$val){

$balanced=true;

$remaining=replace_once($remaining,$val,"");

$val=substr($val,1,strlen($val)-2);

$balanced=is_balanced($val);

if(!$balanced){

returnfalse;

}

}

returnis_balanced($remaining);

}else{

$string=str_replace(array(":)",":("),array("",""),$string);

$open=0;

for($i=0;$i<strlen($string);$i++){

if($string[$i]==")"){

if($open>0){

$open--;

}else{

returnfalse;

}

}

if($string[$i]=="("){

$open++;

}

}

if($open==0){

returntrue;

}else{

returnfalse;

}

}

}

$handle=fopen("output.txt","w+");

for($case=1;$case<=$row_count;$case++){

$row=$rows[$case];

if(is_balanced($row)){

print("Case #$case: YES\n");

fwrite($handle,"Case #$case: YES\n");

}else{

print("Case #$case: NO\n");

fwrite($handle,"Case #$case: NO\n");

}

}

fclose($handle);

Task 3: Find the min

After sending smileys, John decided to play with arrays. Did you know that hackers enjoy playing with arrays? John has a zero-based index array, m, which contains n non-negative integers. However, only the first k values of the array are known to him, and he wants to figure out the rest.

John knows the following: for each index i, where k <= i < n, m[i] is the minimum non-negative integer which is *not* contained in the previous *k* values of m.
For example, if k = 3, n = 4 and the known values of m are [2, 3, 0], he can figure out that m[3] = 1.
John is very busy making the world more open and connected, as such, he doesn't have time to figure out the rest of the array. It is your task to help him.
Given the first k values of m, calculate the nth value of this array. (i.e. m[n - 1]).
Because the values of n and k can be very large, we use a pseudo-random number generator to calculate the first k values of m. Given positive integers a, b, c and r, the known values of m can be calculated as follows:
m[0] = a
m[i] = (b * m[i - 1] + c) % r, 0 < i < k
Input
The first line contains an integer T (T <= 20), the number of test cases.
This is followed by T test cases, consisting of 2 lines each.
The first line of each test case contains 2 space separated integers, n, k (1 <= k <= 10^5, k < n <= 10^9).
The second line of each test case contains 4 space separated integers a, b, c, r (0 <= a, b, c <= 10^9, 1 <= r <= 10^9).
Output
For each test case, output a single line containing the case number and the nth element of m.

Well, I failed this task. Not because my solution wasn’t working. It wasn’t fast enough in some cases. I considered seed (it is not my first time on the Hacker cup) and tested it with large arrays but I missed a case when my script fails. The key speed up was when I realized that the analyzed array slices are repeating. They are repeating after every Kth element, therefor:

PHP

1

2

3

if($n>$k*2){

$n=$k+($n%$k)-1;

}

It gave me a huge speed up, but apparently not enough. I tried to run my script with the test cases provided by Facebook’s system and it didn’t finish in the 6 minutes limit even on the high-compute Amazon EC2 instances. Epic fail. Well next time. Anyway, my solution for task #3:

Every documentation and every code piece you can find about PHP’s header(“location: ….”); function recommends using die(); after the statement, but I never realized why until a couple of days ago. Most of the times I use die(); or exit(); after redirect statements, but for some reason I forgot to do so in one of my script. I learned the hard way why is it important: someone gained partial access to my site’s admin area. Turns out you can turn off redirects in your browser and in that case the rest of the script will execute without problems. Rookie mistake, I know, but I thought it’s worth sharing

register_shutdown_function
Recently I was building a PHP based load balancer for handling long running (video streams, sometimes up to 1 hour) processes. My biggest problem were if the user closed the page the load balancer had to react. This handy function is the best solution for the problem. Basically it calls the callback function when the script’s execution finishes or the user closes the browser window

scandir
If you are tired of using opendir, readdir and closedir, this function is for you

glob
Even better than scandir. It will only list the files matching the pattern passed in as an argument

CURLOPT_PROGRESSFUNCTION
This is a fairly new feature of the curl library. You can specify a callback function which will be executed every time a chunk of data comes back from the remote host. Usually I’m using it to create progress bars for long running curl processes

escapeshellcmd
I’m dealing with loads of user generated files in many different languages. As you may know the golden rule: “Users are idiots” so they put spaces, quotes and many many random characters in the file names. escapeshellcmd is a really handy function to escape a command before you call exec