SlideShare a Scribd company logo
Php Cookbook Solutions Examples For Php
Programmers 3rd David Sklar Adam Trachtenberg
download
https://ebookbell.com/product/php-cookbook-solutions-examples-
for-php-programmers-3rd-david-sklar-adam-trachtenberg-4748850
Explore and download more ebooks at ebookbell.com
Here are some recommended products that we believe you will be
interested in. You can click the link to download.
Php Cookbook Modern Code Solutions For Professional Developers 1st
Edition Eric A Mann
https://ebookbell.com/product/php-cookbook-modern-code-solutions-for-
professional-developers-1st-edition-eric-a-mann-53559800
Php Cookbook 2nd Edition David Sklar Adam Trachtenberg
https://ebookbell.com/product/php-cookbook-2nd-edition-david-sklar-
adam-trachtenberg-2244940
Php Cookbook Third Early Release 20220713 Third Early Release Eric A
Mann
https://ebookbell.com/product/php-cookbook-third-early-
release-20220713-third-early-release-eric-a-mann-43887496
Php Cookbook 1st Edition David Sklar Adam Trachtenberg
https://ebookbell.com/product/php-cookbook-1st-edition-david-sklar-
adam-trachtenberg-1213864
Php Cookbook Eric A Mann
https://ebookbell.com/product/php-cookbook-eric-a-mann-232273274
Php Ajax Cookbook Milan Sedliak Rajesh Jeba R Anbiah Roshan Bhattarai
https://ebookbell.com/product/php-ajax-cookbook-milan-sedliak-rajesh-
jeba-r-anbiah-roshan-bhattarai-2490048
Php Jquery Cookbook Vijay Joshi
https://ebookbell.com/product/php-jquery-cookbook-vijay-joshi-2531248
Php Ajax Cookbook Code For Book Sedliak M Anbiah Rrj Bhattarai R
https://ebookbell.com/product/php-ajax-cookbook-code-for-book-sedliak-
m-anbiah-rrj-bhattarai-r-6318474
Php 7 Programming Cookbook Doug Bierer
https://ebookbell.com/product/php-7-programming-cookbook-doug-
bierer-6808568
Php Cookbook Solutions Examples For Php Programmers 3rd David Sklar Adam Trachtenberg
Php Cookbook Solutions Examples For Php Programmers 3rd David Sklar Adam Trachtenberg
Php Cookbook Solutions Examples For Php Programmers 3rd David Sklar Adam Trachtenberg
David Sklar and Adam Trachtenberg
THIRD EDITION
PHP Cookbook
PHP Cookbook, Third Edition
by David Sklar and Adam Trachtenberg
Copyright © 2014 David Sklar and Adam Trachtenberg. All rights reserved.
Printed in the United States of America.
Published by O’Reilly Media, Inc., 1005 Gravenstein Highway North, Sebastopol, CA 95472.
O’Reilly books may be purchased for educational, business, or sales promotional use. Online editions are
alsoavailableformosttitles(http://my.safaribooksonline.com).Formoreinformation,contactourcorporate/
institutional sales department: 800-998-9938 or corporate@oreilly.com.
Editors:Rachel Roumeliotis and Allyson MacDonald
Production Editor: Melanie Yarbrough
Copyeditor: Kim Cofer
Proofreader: Charles Roumeliotis
Indexer: Judith McConville
Cover Designer: Karen Montgomery
Interior Designer: David Futato
Illustrator: Rebecca Demarest
June 2001: First Edition
June 2004: Second Edition
June 2014: Third Edition
Revision History for the Third Edition:
2014-06-25: First release
See http://oreilly.com/catalog/errata.csp?isbn=9781449363758 for release details.
Nutshell Handbook, the Nutshell Handbook logo, and the O’Reilly logo are registered trademarks of O’Reilly
Media, Inc. PHP Cookbook, the image of a Galapagos land iguana, and related trade dress are trademarks
of O’Reilly Media, Inc.
Many of the designations used by manufacturers and sellers to distinguish their products are claimed as
trademarks.Wherethosedesignationsappearinthisbook,andO’ReillyMedia,Inc.wasawareofatrademark
claim, the designations have been printed in caps or initial caps.
While every precaution has been taken in the preparation of this book, the publisher and authors assume
no responsibility for errors or omissions, or for damages resulting from the use of the information contained
herein.
ISBN: 978-1-449-36375-8
[LSI]
Table of Contents
Preface. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xv
1. Strings. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.1 Accessing Substrings 5
1.2 Extracting Substrings 6
1.3 Replacing Substrings 7
1.4 Processing a String One Byte at a Time 9
1.5 Reversing a String by Word or Byte 10
1.6 Generating a Random String 11
1.7 Expanding and Compressing Tabs 12
1.8 Controlling Case 14
1.9 Interpolating Functions and Expressions Within Strings 16
1.10 Trimming Blanks from a String 17
1.11 Generating Comma-Separated Data 18
1.12 Parsing Comma-Separated Data 20
1.13 Generating Fixed-Width Field Data Records 21
1.14 Parsing Fixed-Width Field Data Records 22
1.15 Taking Strings Apart 25
1.16 Wrapping Text at a Certain Line Length 27
1.17 Storing Binary Data in Strings 28
1.18 Program: Downloadable CSV File 31
2. Numbers. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
2.1 Checking Whether a Variable Contains a Valid Number 36
2.2 Comparing Floating-Point Numbers 37
2.3 Rounding Floating-Point Numbers 38
2.4 Operating on a Series of Integers 40
2.5 Generating Random Numbers Within a Range 42
2.6 Generating Predictable Random Numbers 43
iii
2.7 Generating Biased Random Numbers 44
2.8 Taking Logarithms 46
2.9 Calculating Exponents 46
2.10 Formatting Numbers 47
2.11 Formatting Monetary Values 49
2.12 Printing Correct Plurals 50
2.13 Calculating Trigonometric Functions 51
2.14 Doing Trigonometry in Degrees, Not Radians 52
2.15 Handling Very Large or Very Small Numbers 53
2.16 Converting Between Bases 55
2.17 Calculating Using Numbers in Bases Other Than Decimal 56
2.18 Finding the Distance Between Two Places 58
3. Dates and Times. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
3.1 Finding the Current Date and Time 63
3.2 Converting Time and Date Parts to an Epoch Timestamp 66
3.3 Converting an Epoch Timestamp to Time and Date Parts 68
3.4 Printing a Date or Time in a Specified Format 69
3.5 Finding the Difference of Two Dates 71
3.6 Finding the Day in a Week, Month, or Year 73
3.7 Validating a Date 75
3.8 Parsing Dates and Times from Strings 77
3.9 Adding to or Subtracting from a Date 79
3.10 Calculating Time with Time Zones and Daylight Saving Time 80
3.11 Generating a High-Precision Time 82
3.12 Generating Time Ranges 83
3.13 Using Non-Gregorian Calendars 84
3.14 Program: Calendar 87
4. Arrays. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
4.1 Specifying an Array Not Beginning at Element 0 96
4.2 Storing Multiple Elements per Key in an Array 97
4.3 Initializing an Array to a Range of Integers 99
4.4 Iterating Through an Array 99
4.5 Deleting Elements from an Array 102
4.6 Changing Array Size 104
4.7 Appending One Array to Another 106
4.8 Turning an Array into a String 108
4.9 Printing an Array with Commas 109
4.10 Checking if a Key Is in an Array 110
4.11 Checking if an Element Is in an Array 111
4.12 Finding the Position of a Value in an Array 113
iv | Table of Contents
4.13 Finding Elements That Pass a Certain Test 114
4.14 Finding the Largest or Smallest Valued Element in an Array 115
4.15 Reversing an Array 116
4.16 Sorting an Array 116
4.17 Sorting an Array by a Computable Field 118
4.18 Sorting Multiple Arrays 120
4.19 Sorting an Array Using a Method Instead of a Function 122
4.20 Randomizing an Array 123
4.21 Removing Duplicate Elements from an Array 123
4.22 Applying a Function to Each Element in an Array 124
4.23 Finding the Union, Intersection, or Difference of Two Arrays 126
4.24 Iterating Efficiently over Large or Expensive Datasets 128
4.25 Accessing an Object Using Array Syntax 131
5. Variables. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
5.1 Avoiding == Versus = Confusion 137
5.2 Establishing a Default Value 138
5.3 Exchanging Values Without Using Temporary Variables 139
5.4 Creating a Dynamic Variable Name 140
5.5 Persisting a Local Variable’s Value Across Function Invocations 141
5.6 Sharing Variables Between Processes 143
5.7 Encapsulating Complex Data Types in a String 149
5.8 Dumping Variable Contents as Strings 151
6. Functions. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157
6.1 Accessing Function Parameters 158
6.2 Setting Default Values for Function Parameters 159
6.3 Passing Values by Reference 161
6.4 Using Named Parameters 162
6.5 Enforcing Types of Function Arguments 163
6.6 Creating Functions That Take a Variable Number of Arguments 164
6.7 Returning Values by Reference 167
6.8 Returning More Than One Value 169
6.9 Skipping Selected Return Values 170
6.10 Returning Failure 171
6.11 Calling Variable Functions 172
6.12 Accessing a Global Variable Inside a Function 175
6.13 Creating Dynamic Functions 176
7. Classes and Objects. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179
7.1 Instantiating Objects 183
7.2 Defining Object Constructors 184
Table of Contents | v
7.3 Defining Object Destructors 185
7.4 Implementing Access Control 186
7.5 Preventing Changes to Classes and Methods 189
7.6 Defining Object Stringification 190
7.7 Requiring Multiple Classes to Behave Similarly 191
7.8 Creating Abstract Base Classes 195
7.9 Assigning Object References 197
7.10 Cloning Objects 198
7.11 Overriding Property Accesses 201
7.12 Calling Methods on an Object Returned by Another Method 205
7.13 Aggregating Objects 206
7.14 Accessing Overridden Methods 210
7.15 Creating Methods Dynamically 212
7.16 Using Method Polymorphism 213
7.17 Defining Class Constants 215
7.18 Defining Static Properties and Methods 217
7.19 Controlling Object Serialization 220
7.20 Introspecting Objects 222
7.21 Checking If an Object Is an Instance of a Specific Class 226
7.22 Autoloading Class Files upon Object Instantiation 229
7.23 Instantiating an Object Dynamically 230
7.24 Program: whereis 231
8. Web Fundamentals. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235
8.1 Setting Cookies 236
8.2 Reading Cookie Values 238
8.3 Deleting Cookies 238
8.4 Building a Query String 239
8.5 Reading the POST Request Body 240
8.6 Using HTTP Basic or Digest Authentication 241
8.7 Using Cookie Authentication 245
8.8 Reading an HTTP Header 248
8.9 Writing an HTTP Header 249
8.10 Sending a Specific HTTP Status Code 250
8.11 Redirecting to a Different Location 251
8.12 Flushing Output to the Browser 252
8.13 Buffering Output to the Browser 253
8.14 Compressing Web Output 255
8.15 Reading Environment Variables 255
8.16 Setting Environment Variables 256
8.17 Communicating Within Apache 257
8.18 Redirecting Mobile Browsers to a Mobile Optimized Site 258
vi | Table of Contents
8.19 Program: Website Account (De)activator 259
8.20 Program: Tiny Wiki 262
8.21 Program: HTTP Range 265
9. Forms. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275
9.1 Processing Form Input 277
9.2 Validating Form Input: Required Fields 279
9.3 Validating Form Input: Numbers 281
9.4 Validating Form Input: Email Addresses 283
9.5 Validating Form Input: Drop-Down Menus 284
9.6 Validating Form Input: Radio Buttons 285
9.7 Validating Form Input: Checkboxes 287
9.8 Validating Form Input: Dates and Times 289
9.9 Validating Form Input: Credit Cards 290
9.10 Preventing Cross-Site Scripting 291
9.11 Processing Uploaded Files 292
9.12 Working with Multipage Forms 295
9.13 Redisplaying Forms with Inline Error Messages 296
9.14 Guarding Against Multiple Submissions of the Same Form 299
9.15 Preventing Global Variable Injection 301
9.16 Handling Remote Variables with Periods in Their Names 303
9.17 Using Form Elements with Multiple Options 304
9.18 Creating Drop-Down Menus Based on the Current Date 305
10. Database Access. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307
10.1 Using DBM Databases 310
10.2 Using an SQLite Database 313
10.3 Connecting to an SQL Database 315
10.4 Querying an SQL Database 316
10.5 Retrieving Rows Without a Loop 319
10.6 Modifying Data in an SQL Database 320
10.7 Repeating Queries Efficiently 321
10.8 Finding the Number of Rows Returned by a Query 324
10.9 Escaping Quotes 325
10.10 Logging Debugging Information and Errors 327
10.11 Creating Unique Identifiers 329
10.12 Building Queries Programmatically 331
10.13 Making Paginated Links for a Series of Records 336
10.14 Caching Queries and Results 339
10.15 Accessing a Database Connection Anywhere in Your Program 341
10.16 Program: Storing a Threaded Message Board 343
Table of Contents | vii
10.17 Using Redis 351
11. Sessions and Data Persistence. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 353
11.1 Using Session Tracking 354
11.2 Preventing Session Hijacking 356
11.3 Preventing Session Fixation 357
11.4 Storing Sessons in Memcached 358
11.5 Storing Sessions in a Database 359
11.6 Storing Arbitrary Data in Shared Memory 362
11.7 Caching Calculated Results in Summary Tables 365
12. XML. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 369
12.1 Generating XML as a String 372
12.2 Generating XML with DOM 373
12.3 Parsing Basic XML Documents 376
12.4 Parsing Complex XML Documents 379
12.5 Parsing Large XML Documents 381
12.6 Extracting Information Using XPath 387
12.7 Transforming XML with XSLT 390
12.8 Setting XSLT Parameters from PHP 392
12.9 Calling PHP Functions from XSLT Stylesheets 394
12.10 Validating XML Documents 398
12.11 Handling Content Encoding 400
12.12 Reading RSS and Atom Feeds 401
12.13 Writing RSS Feeds 404
12.14 Writing Atom Feeds 407
13. Web Automation. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 413
13.1 Marking Up a Web Page 414
13.2 Cleaning Up Broken or Nonstandard HTML 416
13.3 Extracting Links from an HTML File 420
13.4 Converting Plain Text to HTML 422
13.5 Converting HTML to Plain Text 423
13.6 Removing HTML and PHP Tags 424
13.7 Responding to an Ajax Request 428
13.8 Integrating with JavaScript 429
13.9 Program: Finding Stale Links 433
13.10 Program: Finding Fresh Links 435
14. Consuming RESTful APIs. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 439
14.1 Fetching a URL with the GET Method 440
14.2 Fetching a URL with the POST Method and Form Data 444
viii | Table of Contents
14.3 Fetching a URL with an Arbitrary Method and POST Body 446
14.4 Fetching a URL with Cookies 448
14.5 Fetching a URL with Arbitrary Headers 450
14.6 Fetching a URL with a Timeout 451
14.7 Fetching an HTTPS URL 453
14.8 Debugging the Raw HTTP Exchange 453
14.9 Making an OAuth 1.0 Request 458
14.10 Making an OAuth 2.0 Request 460
15. Serving RESTful APIs. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 465
15.1 Exposing and Routing to a Resource 468
15.2 Exposing Clean Resource Paths 471
15.3 Exposing a Resource for Reading 472
15.4 Creating a Resource 474
15.5 Editing a Resource 479
15.6 Deleting a Resource 481
15.7 Indicating Errors and Failures 482
15.8 Supporting Multiple Formats 484
16. Internet Services. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 487
16.1 Sending Mail 488
16.2 Sending MIME Mail 490
16.3 Reading Mail with IMAP or POP3 491
16.4 Getting and Putting Files with FTP 495
16.5 Looking Up Addresses with LDAP 498
16.6 Using LDAP for User Authentication 499
16.7 Performing DNS Lookups 502
16.8 Checking If a Host Is Alive 504
16.9 Getting Information About a Domain Name 506
17. Graphics. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 509
17.1 Drawing Lines, Rectangles, and Polygons 512
17.2 Drawing Arcs, Ellipses, and Circles 515
17.3 Drawing with Patterned Lines 517
17.4 Drawing Text 518
17.5 Drawing Centered Text 520
17.6 Building Dynamic Images 524
17.7 Getting and Setting a Transparent Color 526
17.8 Overlaying Watermarks 527
17.9 Creating Thumbnail Images 530
17.10 Reading EXIF Data 533
17.11 Serving Images Securely 535
Table of Contents | ix
17.12 Program: Generating Bar Charts from Poll Results 536
18. Security and Encryption. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 541
18.1 Preventing Session Fixation 542
18.2 Protecting Against Form Spoofing 543
18.3 Ensuring Input Is Filtered 544
18.4 Avoiding Cross-Site Scripting 545
18.5 Eliminating SQL Injection 546
18.6 Keeping Passwords Out of Your Site Files 547
18.7 Storing Passwords 548
18.8 Dealing with Lost Passwords 551
18.9 Verifying Data with Hashes 553
18.10 Encrypting and Decrypting Data 555
18.11 Storing Encrypted Data in a File or Database 557
18.12 Sharing Encrypted Data with Another Website 560
18.13 Detecting SSL 562
18.14 Encrypting Email with GPG 563
19. Internationalization and Localization. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 567
19.1 Determining the User’s Locale 569
19.2 Localizing Text Messages 570
19.3 Localizing Dates and Times 573
19.4 Localizing Numbers 577
19.5 Localizing Currency Values 579
19.6 Localizing Images 581
19.7 Localizing Included Files 583
19.8 Sorting in a Locale-Aware Order 584
19.9 Managing Localization Resources 584
19.10 Setting the Character Encoding of Outgoing Data 587
19.11 Setting the Character Encoding of Incoming Data 587
19.12 Manipulating UTF-8 Text 588
20. Error Handling. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 593
20.1 Finding and Fixing Parse Errors 594
20.2 Creating Your Own Exception Classes 596
20.3 Printing a Stack Trace 599
20.4 Reading Configuration Variables 602
20.5 Setting Configuration Variables 603
20.6 Hiding Error Messages from Users 604
20.7 Tuning Error Handling 606
20.8 Using a Custom Error Handler 608
20.9 Logging Errors 609
x | Table of Contents
20.10 Eliminating “headers already sent” Errors 611
20.11 Logging Debugging Information 612
21. Software Engineering. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 615
21.1 Using a Debugger Extension 615
21.2 Writing a Unit Test 619
21.3 Writing a Unit Test Suite 620
21.4 Applying a Unit Test to a Web Page 622
21.5 Setting Up a Test Environment 624
21.6 Using the Built-in Web Server 625
22. Performance Tuning. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 629
22.1 Using an Accelerator 630
22.2 Timing Function Execution 631
22.3 Timing Program Execution by Function 632
22.4 Timing Program Execution by Statement 634
22.5 Timing Program Execution by Section 636
22.6 Profiling with a Debugger Extension 638
22.7 Stress-Testing Your Website 642
22.8 Avoiding Regular Expressions 643
23. Regular Expressions. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 647
23.1 Switching from ereg to preg 651
23.2 Matching Words 652
23.3 Finding the nth Occurrence of a Match 654
23.4 Choosing Greedy or Nongreedy Matches 656
23.5 Finding All Lines in a File That Match a Pattern 658
23.6 Capturing Text Inside HTML Tags 659
23.7 Preventing Parentheses from Capturing Text 660
23.8 Escaping Special Characters in a Regular Expression 662
23.9 Reading Records with a Pattern Separator 663
23.10 Using a PHP Function in a Regular Expression 664
24. Files. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 667
24.1 Creating or Opening a Local File 671
24.2 Creating a Temporary File 672
24.3 Opening a Remote File 673
24.4 Reading from Standard Input 674
24.5 Reading a File into a String 675
24.6 Counting Lines, Paragraphs, or Records in a File 676
24.7 Processing Every Word in a File 679
24.8 Picking a Random Line from a File 680
Table of Contents | xi
24.9 Randomizing All Lines in a File 681
24.10 Processing Variable-Length Text Fields 682
24.11 Reading Configuration Files 683
24.12 Modifying a File in Place Without a Temporary File 685
24.13 Flushing Output to a File 687
24.14 Writing to Standard Output 688
24.15 Writing to Many Filehandles Simultaneously 688
24.16 Escaping Shell Metacharacters 689
24.17 Passing Input to a Program 691
24.18 Reading Standard Output from a Program 692
24.19 Reading Standard Error from a Program 693
24.20 Locking a File 694
24.21 Reading and Writing Custom File Types 697
24.22 Reading and Writing Compressed Files 702
25. Directories. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 705
25.1 Getting and Setting File Timestamps 708
25.2 Getting File Information 709
25.3 Changing File Permissions or Ownership 710
25.4 Splitting a Filename into Its Component Parts 711
25.5 Deleting a File 713
25.6 Copying or Moving a File 713
25.7 Processing All Files in a Directory 714
25.8 Getting a List of Filenames Matching a Pattern 715
25.9 Processing All Files in a Directory Recursively 717
25.10 Making New Directories 717
25.11 Removing a Directory and Its Contents 718
25.12 Program: Web Server Directory Listing 719
25.13 Program: Site Search 723
26. Command-Line PHP. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 727
26.1 Parsing Program Arguments 729
26.2 Parsing Program Arguments with getopt 730
26.3 Reading from the Keyboard 732
26.4 Running PHP Code on Every Line of an Input File 734
26.5 Reading Passwords 736
26.6 Colorizing Console Output 738
26.7 Program: DOM Explorer 740
27. Packages. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 745
27.1 Defining and Installing Composer Dependencies 748
27.2 Finding Composer Packages 749
xii | Table of Contents
27.3 Installing Composer Packages 751
27.4 Using the PEAR Installer 754
27.5 Finding PEAR Packages 757
27.6 Finding Information About a Package 759
27.7 Installing PEAR Packages 760
27.8 Upgrading PEAR Packages 762
27.9 Uninstalling PEAR Packages 763
27.10 Installing PECL Packages 764
Index. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 767
Table of Contents | xiii
Php Cookbook Solutions Examples For Php Programmers 3rd David Sklar Adam Trachtenberg
Preface
PHP is the engine behind millions of dynamic web applications. Its broad feature set,
approachable syntax, and support for different operating systems and web servers have
made it an ideal language for both rapid web development and the methodical con‐
struction of complex systems.
One of the major reasons for PHP’s success as a web scripting language is its origins as
atooltoprocessHTMLformsandcreatewebpages.ThismakesPHPveryweb-friendly.
Additionally, it is eagerly promiscuous when it comes to external applications and li‐
braries. PHP can speak to a multitude of databases, and it knows numerous Internet
protocols. PHP also makes it simple to parse form data and make HTTP requests. This
web-specific focus carries over to the recipes and examples in the PHP Cookbook.
This book is a collection of solutions to common tasks in PHP. We’ve tried to include
material that will appeal to everyone from newbies to wizards. If we’ve succeeded, you’ll
learn something (or perhaps many things) from PHP Cookbook. There are tips in here
for everyday PHP programmers as well as for people coming to PHP with experience
in another language.
PHP, in source code and binary forms, is available for download free from http://
www.php.net/. The PHP website also contains installation instructions, comprehensive
documentation, and pointers to online resources, user groups, mailing lists, and other
PHP resources.
Who This Book Is For
This book is for programmers who need to solve problems with PHP. If you don’t know
any PHP, make this your second PHP book. The first should be Learning PHP 5, also
from O’Reilly.
If you’re already familiar with PHP, this book helps you overcome a specific problem
and get on with your life (or at least your programming activities). The PHP Cook‐
xv
book can also show you how to accomplish a particular task in PHP, such as sending
email or parsing JSON, that you may already know how to do in another language.
Programmers converting applications from other languages to PHP will find this book
a trusty companion.
What Is in This Book
We don’t expect that you’ll sit down and read this book from cover to cover (although
we’ll be happy if you do!). PHP programmers are constantly faced with a wide variety
of challenges on a wide range of subjects. Turn to the PHP Cookbook when you en‐
counter a problem you need to solve. Each recipe is a self-contained explanation that
gives you a head start toward finishing your task. When a recipe refers to topics outside
its scope, it contains pointers to related recipes and other online and offline resources.
If you choose to read an entire chapter at once, that’s OK. The recipes generally flow
from easy to hard, with example programs that “put it all together” at the end of many
chapters. The chapter introduction provides an overview of the material covered in the
chapter, including relevant background material, and points out a few highlighted rec‐
ipes of special interest.
The book begins with four chapters about basic data types. Chapter 1 covers details like
processing substrings, manipulating case, taking strings apart into smaller pieces, and
parsing comma-separated data. Chapter 2 explains operations with floating-point num‐
bers, random numbers, converting between bases, and number formatting. Chapter 3
shows you how to manipulate dates and times, format them, handle time zones and
daylight saving time, and find time to microsecond precision. Chapter 4 covers array
operationslikeiterating,merging,reversing,sorting,andextractingparticularelements.
Next are three chapters that discuss program building blocks. Chapter 5 covers notable
features of PHP’s variable handling, such as default values, static variables, and pro‐
ducing string representations of complex data types. The recipes in Chapter 6 deal with
using functions in PHP: processing arguments, passing and returning variables by ref‐
erence, creating functions at runtime, and scoping variables. Chapter 7 covers PHP’s
object-oriented capabilities, with recipes on OOP basics as well as more advanced fea‐
tures, such as magic methods, destructors, access control, reflection, traits, and name‐
spaces.
After the data types and building blocks come six chapters devoted to topics that are
central to web programming. Chapter 8 covers cookies, headers, authentication, work‐
ing with query strings, and other fundamentals of web applications. Chapter 9 covers
processing and validating form input, displaying multipage forms, showing forms with
error messages, and guarding against problems such as cross-site scripting and multiple
submissions of the same form. Chapter 10 explains the differences between DBM and
SQL databases and, using the PDO database access abstraction layer, shows how to
xvi | Preface
connecttoadatabase,assignuniqueIDvalues,retrieverows,changedata,escapequotes,
and log debugging information. Chapter 11 covers PHP’s built-in sessions module,
which lets you maintain information about a user as he moves from page to page on
your website. This chapter also highlights some of the security issues associated with
sessions. Chapter 12 discusses all things XML: the SimpleXML extension and DOM
functions, using XPath and XSLT, and reading and writing both RSS and Atom feeds.
Chapter 13 explores topics useful to PHP applications that integrate with external web‐
sites and client-side JavaScript such as retrieving remote URLs, cleaning up HTML, and
responding to an Ajax request.
The next three chapters are all about network interaction. Chapter 14 details the ins and
outs of consuming a web service—using an external REST service from within your
code. Chapter 15 handles the other side of the web services equation—serving up REST
requests to others. Both chapters discuss authentication, headers, and error handling.
Chapter 16 discusses other network services such as sending email messages, using
LDAP, and doing DNS lookups.
The next section of the book is a series of chapters on features and extensions of PHP
that help you build applications that are robust, secure, user-friendly, and efficient.
Chapter 17 shows you how to create graphics, with recipes on drawing text, lines,
polygons, and curves. Chapter 18 focuses on security topics such as avoiding session
fixation and cross-site scripting, working with passwords, and encrypting data. Chap‐
ter 19 helps you make your applications globally friendly and includes recipes for lo‐
calizing text, dates and times, currency values, and images, as well as a recipe working
with text in UTF-8 character encoding. Chapter 20 goes into detail on error handling
and logging, while Chapter 21 discusses debugging techniques, writing tests for your
code, and using PHP’s built-in web server. Chapter 22 explains how to compare the
performance of two functions and provides tips on getting your programs to run at
maximum speed. Chapter 23 covers regular expressions, including capturing text inside
ofHTMLtags,callingaPHPfunctionfrominsidearegularexpression,andusinggreedy
and nongreedy matching.
Chapters24and25coverthefilesystem.Chapter24focusesonfiles:openingandclosing
them, using temporary files, locking files, sending compressed files, and processing the
contents of files. Chapter 25 deals with directories and file metadata, with recipes on
changing file permissions and ownership, moving or deleting a file, and processing all
files in a directory.
Last, there are two chapters on topics that extend the reach of what PHP can do. Chap‐
ter 26 covers using PHP outside of web programming. Its recipes cover command-line
topics such as parsing program arguments and reading passwords. Chapter 27 covers
Composer, PEAR (PHP Extension and Application Repository), and PECL (PHP Ex‐
tension Community Library). Composer and PEAR provide access to a collection of
PHP code that provides functions and extensions to PHP. PECL is a similar collection,
Preface | xvii
but of extensions to PHP written in C. We use PEAR and PECL modules throughout
the book and Chapter 27 shows you how to install and upgrade them.
Other Resources
Websites
There is a tremendous amount of PHP reference material online. With everything from
the annotated PHP manual to sites with periodic articles and tutorials, a fast Internet
connection rivals a large bookshelf in PHP documentary usefulness. Here are some key
sites:
The Annotated PHP Manual
Availablein11languages,thissiteincludesbothofficialdocumentationoffunctions
and language features as well as user-contributed comments.
PHP mailing lists
There are many PHP mailing lists covering installation, programming, extending
PHP, and various other topics; there is also a read-only web interface to the mailing
lists.
PHP support resources
This handy collection of support resources has information on PHP user groups,
events, and other support channels.
Composer
Composer is a dependency manager for PHP that provides a structured way both
to declare dependencies in your project and to install them.
PEAR
PEAR calls itself “a framework and distribution system for reusable PHP compo‐
nents.” You’ll find lots of useful PHP classes and sample code there. Read more
about PEAR in Chapter 27.
PECL
PECL calls itself “a repository for PHP Extensions, providing a directory of exten‐
sions and hosting facilities for downloading and development of PHP extensions.”
Read more about PECL in Chapter 27.
PHP.net: A Tourist’s Guide
This is a guide to the various websites under the php.net umbrella.
PHP: The Right Way
A quick reference that attempts to be a comprehensive source of PHP best practices.
A great place to start if you’re wondering about the idiomatic way to do something
in PHP.
xviii | Preface
Planet PHP
An aggregation of blog posts by PHP developers, about PHP.
SitePoint Blogs on PHP
A good collection of information that explores PHP.
Books
Thissectionlistsbooksthatarehelpfulreferencesandtutorialsforbuildingapplications
with PHP. Most are specific to web-related programming; look for books on MySQL,
HTML, XML, and HTTP.
At the end of the section, we’ve included a few books that are useful for every program‐
mer regardless of language of choice. These works can make you a better programmer
by teaching you how to think about programming as part of a larger pattern of problem
solving:
• Learning PHP 5 by David Sklar (O’Reilly)
• Programming PHP by Rasmus Lerdorf, Kevin Tatroe, and Peter MacIntyre (O’Reil‐
ly)
• Extending and Embedding PHP by Sara Golemon (Sams)
• Learning PHP, MySQL, JavaScript, and CSS by Robin Nixon (O’Reilly)
• Mastering Regular Expressions by Jeffrey E. F. Friedl (O’Reilly)
• MySQL Reference Manual
• MySQL, by Paul DuBois (New Riders)
• The Practice of Programming, by Brian W. Kernighan and Rob Pike (Addison-
Wesley)
• Programming Pearls by Jon Louis Bentley (Addison-Wesley)
• The Mythical Man-Month, by Frederick P. Brooks (Addison-Wesley)
Conventions Used in This Book
Programming Conventions
The examples in this book were written to run under PHP version 5.4.28 (and, where
applicable, PHP 5.5.12). Sample code should work on both Unix and Windows, except
where noted in the text. We’ve generally noted in the text when we depend on a feature
added to PHP in or after 5.5.
Preface | xix
Some examples rely on the $php_errormsg variable, which is only available when the
track_errors configuration directive is turned on.
Typesetting Conventions
The following typographic conventions are used in this book:
Italic
Used for commands, filenames, and example URLs. It is also used to define new
terms when they first appear in the text.
Constant width
Used in code examples to show partial or complete PHP source code program
listings. It is also used for class names, method names, variable names, and other
fragments of PHP code.
Constant width bold
Used for user input, such as commands that you type on the command line.
Constant width italic
Shows text that should be replaced with user-supplied values or by values deter‐
mined by context.
Comments and Questions
Please address comments and questions concerning this book to the publisher:
O’Reilly Media, Inc.
1005 Gravenstein Highway North
Sebastopol, CA 95472
800-998-9938 (in the United States or Canada)
707-829-0515 (international or local)
707-829-0104 (fax)
We have a web page for this book, where we list errata, examples, and any additional
information. You can access this page at http://bit.ly/phpckbk3.
To comment or ask technical questions about this book, send email to bookques
tions@oreilly.com.
For more information about our books, courses, conferences, and news, see our website
at http://www.oreilly.com.
Find us on Facebook: http://facebook.com/oreilly
Follow us on Twitter: http://twitter.com/oreillymedia
Watch us on YouTube: http://www.youtube.com/oreillymedia
xx | Preface
Acknowledgments
Most importantly, a huge thanks to everyone who has contributed their time, creativity,
and skills to making PHP what it is today. This amazing volunteer effort has created not
only hundreds of thousands of lines of source code, but also comprehensive documen‐
tation, a QA infrastructure, lots of add-on applications and libraries, and a thriving user
community worldwide. It’s a thrill and an honor to add the PHP Cookbook to the world
of PHP.
Thanks also to our reviewers: Paul Huff, Peter MacIntyre, Simon MacIntyre, and Russ
Uman. Special mention to Chris Shiflett and Clay Lovelace for their contributions to
the second edition of this book.
And big thanks to the folks at O’Reilly that made this book a reality: Rachel Roumeliotis,
Allyson MacDonald, Melanie Yarbrough, and Maria Gulick as well as the nameless orcs
and dwarves that toil in the subterranean caverns of Sebastopol and Cambridge to make
sure that the production process runs smoothly.
David Sklar
Thanks twice again to Adam. We’ve been working together (in one way or another) for
18 years and PHPing together for 17. There is still no one with whom I’d rather have
written this book (except, to be completely honest, maybe Ben Franklin, if he could
somehow be brought back to life).
Thanks to my family members of all ages. You gave me the time and space to focus on
the book. Now I will give you time and space to read the entire thing!
Adam Trachtenberg
David: It’s tough to complete with Ben Franklin. Please know that I support the turkey
as the official animal of PHP instead of the elephant. Many thanks for your support over
all these years, beginning long ago in the days of PHP/FI. Without you, this book would
merely be a dream.
Thanks to my family and friends for their support and encouragement over these many
months. All my love to my two sons, even the one who helped me relearn that human
children don’t give you extensions after 40 weeks if your work on PHP Cookbook isn’t
complete. Finally, special thanks to my wife Elizabeth Anne; I should take your good
advice more often.
Preface | xxi
Php Cookbook Solutions Examples For Php Programmers 3rd David Sklar Adam Trachtenberg
CHAPTER 1
Strings
1.0 Introduction
Strings in PHP are sequences of bytes, such as “We hold these truths to be self-evident”
or “Once upon a time” or even “111211211.” When you read data from a file or output
it to a web browser, your data is represented as strings.
PHP strings are binary-safe (i.e., they can contain null bytes) and can grow and shrink
on demand. Their size is limited only by the amount of memory that is available to PHP.
Usually, PHP strings are ASCII strings. You must do extra work to
handle non-ASCII data like UTF-8 or other multibyte character en‐
codings (see Chapter 19).
Similar in form and behavior to Perl and the Unix shell, strings can be initialized in
three ways: with single quotes, with double quotes, and with the “here document”
(heredoc) format. With single-quoted strings, the only special characters you need to
escape inside a string are the backslash and the single quote itself. This example shows
four single-quoted strings:
print 'I have gone to the store.';
print 'I've gone to the store.';
print 'Would you pay $1.75 for 8 ounces of tap water?';
print 'In double-quoted strings, newline is represented by n';
It prints:
I have gone to the store.
I've gone to the store.
Would you pay $1.75 for 8 ounces of tap water?
In double-quoted strings, newline is represented by n
1
The preceding output shows what the raw output looks like. If you
view it in a web browser, you will see all the sentences on the same
line because HTML requires additional markup to insert line breaks.
Because PHP doesn’t check for variable interpolation or almost any escape sequences
in single-quoted strings, defining strings this way is straightforward and fast.
Double-quoted strings don’t recognize escaped single quotes, but they do recognize
interpolated variables and the escape sequences shown in Table 1-1.
Table 1-1. Double-quoted string escape sequences
Escape sequence Character
n Newline (ASCII 10)
r Carriage return (ASCII 13)
t Tab (ASCII 9)
 Backslash
$ Dollar sign
" Double quote
0 through 777 Octal value
x0 through xFF Hex value
Example 1-1 shows some double-quoted strings.
Example 1-1. Double-quoted strings
print "I've gone to the store.";
print "The sauce cost $10.25.";
$cost = '$10.25';
print "The sauce cost $cost.";
print "The sauce cost $061060.x32x35.";
Example 1-1 prints:
I've gone to the store.
The sauce cost $10.25.
The sauce cost $10.25.
The sauce cost $10.25.
The last line of Example 1-1 prints the price of sauce correctly because the character 1
is ASCII code 49 decimal and 061 octal. Character 0 is ASCII 48 decimal and 060 octal;
2 is ASCII 50 decimal and 32 hex; and 5 is ASCII 53 decimal and 35 hex.
Heredoc-specified strings recognize all the interpolations and escapes of double-quoted
strings, but they don’t require double quotes to be escaped. Heredocs start with <<< and
2 | Chapter 1: Strings
a token. That token (with no leading or trailing whitespace), followed by a semicolon
to end the statement (if necessary), ends the heredoc. Example 1-2 shows how to define
a heredoc.
Example 1-2. Defining a here document
print <<< END
It's funny when signs say things like:
Original "Root" Beer
"Free" Gift
Shoes cleaned while "you" wait
or have other misquoted words.
END;
Example 1-2 prints:
It's funny when signs say things like:
Original "Root" Beer
"Free" Gift
Shoes cleaned while "you" wait
or have other misquoted words.
Newlines, spacing, and quotes are all preserved in a heredoc. By convention, the end-
of-string identifier is usually all caps, and it is case sensitive. Example 1-3 shows two
more valid heredocs.
Example 1-3. More here documents
print <<< PARSLEY
It's easy to grow fresh:
Parsley
Chives
on your windowsill
PARSLEY;
print <<< DOGS
If you like pets, yell out:
DOGS AND CATS ARE GREAT!
DOGS;
Heredocs are especially useful for printing out HTML with interpolated variables be‐
cause you don’t have to escape the double quotes that appear in the HTML elements.
Example 1-4 uses a heredoc to print HTML.
Example 1-4. Printing HTML with a here document
if ($remaining_cards > 0) {
$url = '/deal.php';
$text = 'Deal More Cards';
} else {
$url = '/new-game.php';
$text = 'Start a New Game';
}
1.0 Introduction | 3
print <<< HTML
There are <b>$remaining_cards</b> left.
<p>
<a href="$url">$text</a>
HTML;
In Example 1-4, the semicolon needs to go after the end-of-string delimiter to tell PHP
the statement is ended. In some cases, however, you shouldn’t use the semicolon. One
of these cases is shown in Example 1-5, which uses a heredoc with the string concate‐
nation operator.
Example 1-5. Concatenation with a here document
$html = <<< END
<div class="$divClass">
<ul class="$ulClass">
<li>
END
. $listItem . '</li></div>';
print $html;
Assuming some reasonable values for the $divClass, $ulClass, and $listItem vari‐
ables, Example 1-5 prints:
<div class="class1">>
<ul class="class2">
<li> The List Item </li></div>
In Example 1-5, the expression needs to continue on the next line, so you don’t use a
semicolon. Note also that in order for PHP to recognize the end-of-string delimiter,
the . string concatenation operator needs to go on a separate line from the end-of-string
delimiter.
Nowdocs are similar to heredocs, but there is no variable interpolation. So, nowdocs
are to heredocs as single-quoted strings are to double-quoted strings. They’re best when
you have a block of non-PHP code, such as JavaScript, that you want to print as part of
an HTML page or send to another program.
For example, if you’re using jQuery:
$js = <<<'__JS__'
$.ajax({
'url': '/api/getStock',
'data': {
'ticker': 'LNKD'
},
'success': function( data ) {
$( "#stock-price" ).html( "<strong>$" + data + "</strong>" );
}
});
4 | Chapter 1: Strings
__JS__;
print $js;
Individual bytes in strings can be referenced with square brackets. The first byte in the
string is at index 0. Example 1-6 grabs one byte from a string.
Example 1-6. Getting an individual byte in a string
$neighbor = 'Hilda';
print $neighbor[3];
Example 1-6 prints:
d
1.1 Accessing Substrings
Problem
You want to know if a string contains a particular substring. For example, you want to
find out if an email address contains a @.
Solution
Use strpos(), as in Example 1-7.
Example 1-7. Finding a substring with strpos( )
if (strpos($_POST['email'], '@') === false) {
print 'There was no @ in the e-mail address!';
}
Discussion
The return value from strpos() is the first position in the string (the “haystack”) at
which the substring (the “needle”) was found. If the needle wasn’t found at all in the
haystack, strpos() returns false. If the needle is at the beginning of the haystack,
strpos() returns 0 because position 0 represents the beginning of the string. To dif‐
ferentiate between return values of 0 and false, you must use the identity operator
(===) or the not–identity operator (!==) instead of regular equals (==) or not-equals
(!=). Example 1-7 compares the return value from strpos() to false using ===. This
test only succeeds if strpos() returns false, not if it returns 0 or any other number.
See Also
Documentation on strpos().
1.1 Accessing Substrings | 5
1.2 Extracting Substrings
Problem
You want to extract part of a string, starting at a particular place in the string. For
example, you want the first eight characters of a username entered into a form.
Solution
Use substr() to select your substring, as in Example 1-8.
Example 1-8. Extracting a substring with substr( )
$substring = substr($string,$start,$length);
$username = substr($_GET['username'],0,8);
Discussion
If $start and $length are positive, substr() returns $length characters in the string,
starting at $start. The first character in the string is at position 0. Example 1-9 has
positive $start and $length.
Example 1-9. Using substr( ) with positive $start and $length
print substr('watch out for that tree',6,5);
Example 1-9 prints:
out f
If you leave out $length, substr() returns the string from $start to the end of the
original string, as shown in Example 1-10.
Example 1-10. Using substr( ) with positive start and no length
print substr('watch out for that tree',17);
Example 1-10 prints:
t tree
If $start is bigger than the length of the string, substr() returns false.
If $start plus $length goes past the end of the string, substr() returns all of the string
from $start forward, as shown in Example 1-11.
Example 1-11. Using substr( ) with length past the end of the string
print substr('watch out for that tree',20,5);
Example 1-11 prints:
6 | Chapter 1: Strings
ree
If $start is negative, substr() counts back from the end of the string to determine
where your substring starts, as shown in Example 1-12.
Example 1-12. Using substr( ) with negative start
print substr('watch out for that tree',-6);
print substr('watch out for that tree',-17,5);
Example 1-12 prints:
t tree
out f
With a negative $start value that goes past the beginning of the string (for example, if
$start is −27 with a 20-character string), substr() behaves as if $start is 0.
If $length is negative, substr() counts back from the end of the string to determine
where your substring ends, as shown in Example 1-13.
Example 1-13. Using substr( ) with negative length
print substr('watch out for that tree',15,-2);
print substr('watch out for that tree',-4,-1);
Example 1-13 prints:
hat tr
tre
See Also
Documentation on substr().
1.3 Replacing Substrings
Problem
You want to replace a substring with a different string. For example, you want to obscure
all but the last four digits of a credit card number before printing it.
Solution
Use substr_replace(), as in Example 1-14.
Example 1-14. Replacing a substring with substr_replace( )
// Everything from position $start to the end of $old_string
// becomes $new_substring
$new_string = substr_replace($old_string,$new_substring,$start);
1.3 Replacing Substrings | 7
// $length characters, starting at position $start, become $new_substring
$new_string = substr_replace($old_string,$new_substring,$start,$length);
Discussion
Without the $length argument, substr_replace() replaces everything from $start
to the end of the string. If $length is specified, only that many characters are replaced:
print substr_replace('My pet is a blue dog.','fish.',12);
print substr_replace('My pet is a blue dog.','green',12,4);
$credit_card = '4111 1111 1111 1111';
print substr_replace($credit_card,'xxxx ',0,strlen($credit_card)-4);
My pet is a fish.
My pet is a green dog.
xxxx 1111
If $start is negative, the new substring is placed by counting $start characters from
the end of $old_string, not from the beginning:
print substr_replace('My pet is a blue dog.','fish.',-9);
print substr_replace('My pet is a blue dog.','green',-9,4);
My pet is a fish.
My pet is a green dog.
If $start and $length are 0, the new substring is inserted at the start of $old_string:
print substr_replace('My pet is a blue dog.','Title: ',0,0);
Title: My pet is a blue dog.
The function substr_replace() is useful when you’ve got text that’s too big to display
all at once, and you want to display some of the text with a link to the rest. Example 1-15
displays the first 25 characters of a message with an ellipsis after it as a link to a page
that displays more text.
Example 1-15. Displaying long text with an ellipsis
$r = mysql_query("SELECT id,message FROM messages WHERE id = $id") or die();
$ob = mysql_fetch_object($r);
printf('<a href="more-text.php?id=%d">%s</a>',
$ob->id, substr_replace($ob->message,' ...',25));
The more-text.php page referenced in Example 1-15 can use the message ID passed in
the query string to retrieve the full message and display it.
See Also
Documentation on substr_replace().
8 | Chapter 1: Strings
1.4 Processing a String One Byte at a Time
Problem
You need to process each byte in a string individually.
Solution
Loop through each byte in the string with for. Example 1-16 counts the vowels in a
string.
Example 1-16. Processing each byte in a string
$string = "This weekend, I'm going shopping for a pet chicken.";
$vowels = 0;
for ($i = 0, $j = strlen($string); $i < $j; $i++) {
if (strstr('aeiouAEIOU',$string[$i])) {
$vowels++;
}
}
Discussion
Processing a string a character at a time is an easy way to calculate the “Look and Say”
sequence, as shown in Example 1-17.
Example 1-17. The Look and Say sequence
function lookandsay($s) {
// initialize the return value to the empty string
$r = '';
// $m holds the character we're counting, initialize to the first
// character in the string
$m = $s[0];
// $n is the number of $m's we've seen, initialize to 1
$n = 1;
for ($i = 1, $j = strlen($s); $i < $j; $i++) {
// if this character is the same as the last one
if ($s[$i] == $m) {
// increment the count of this character
$n++;
} else {
// otherwise, add the count and character to the return value
$r .= $n.$m;
// set the character we're looking for to the current one
$m = $s[$i];
// and reset the count to 1
$n = 1;
}
}
// return the built up string as well as the last count and character
1.4 Processing a String One Byte at a Time | 9
return $r.$n.$m;
}
for ($i = 0, $s = 1; $i < 10; $i++) {
$s = lookandsay($s);
print "$sn";
}
Example 1-17 prints:
1
11
21
1211
111221
312211
13112221
1113213211
31131211131221
13211311123113112211
It’s called the “Look and Say” sequence because each element is what you get by looking
at the previous element and saying what’s in it. For example, looking at the first element,
1, you say “one one.” So the second element is “11.” That’s two ones, so the third element
is “21.” Similarly, that’s one two and one one, so the fourth element is “1211,” and so on.
See Also
Documentation on for; more about the “Look and Say” sequence.
1.5 Reversing a String by Word or Byte
Problem
You want to reverse the words or the bytes in a string.
Solution
Use strrev() to reverse by byte, as in Example 1-18.
Example 1-18. Reversing a string by byte
print strrev('This is not a palindrome.');
Example 1-18 prints:
.emordnilap a ton si sihT
To reverse by words, explode the string by word boundary, reverse the words, and then
rejoin, as in Example 1-19.
10 | Chapter 1: Strings
Example 1-19. Reversing a string by word
$s = "Once upon a time there was a turtle.";
// break the string up into words
$words = explode(' ',$s);
// reverse the array of words
$words = array_reverse($words);
// rebuild the string
$s = implode(' ',$words);
print $s;
Example 1-19 prints:
turtle. a was there time a upon Once
Discussion
Reversing a string by words can also be done all in one line with the code in
Example 1-20.
Example 1-20. Concisely reversing a string by word
$reversed_s = implode(' ',array_reverse(explode(' ',$s)));
See Also
Recipe 24.7 discusses the implications of using something other than a space character
as your word boundary; documentation on strrev() and array_reverse().
1.6 Generating a Random String
Problem
You want to generate a random string.
Solution
Use str_rand():
function str_rand($length = 32,
$characters = ↵
'0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ') {
if (!is_int($length) || $length < 0) {
return false;
}
$characters_length = strlen($characters) - 1;
$string = '';
1.6 Generating a Random String | 11
for ($i = $length; $i > 0; $i--) {
$string .= $characters[mt_rand(0, $characters_length)];
}
return $string;
}
Discussion
PHP has native functions for generating random numbers, but nothing for random
strings. The str_rand() function returns a 32-character string constructed from letters
and numbers.
Pass in an integer to change the length of the returned string. To use an alternative set
of characters, pass them as a string as the second argument. For example, to get a 16-
digit Morse Code:
print str_rand(16, '.-');
.--..-.-.--.----
See Also
Recipe 2.5 for generating random numbers.
1.7 Expanding and Compressing Tabs
Problem
You want to change spaces to tabs (or tabs to spaces) in a string while keeping text
aligned with tab stops. For example, you want to display formatted text to users in a
standardized way.
Solution
Use str_replace() to switch spaces to tabs or tabs to spaces, as shown in Example 1-21.
Example 1-21. Switching tabs and spaces
$rows = $db->query('SELECT message FROM messages WHERE id = 1');
$obj = $rows->fetch(PDO::FETCH_OBJ);
$tabbed = str_replace(' ' , "t", $obj->message);
$spaced = str_replace("t", ' ' , $obj->message);
print "With Tabs: <pre>$tabbed</pre>";
print "With Spaces: <pre>$spaced</pre>";
12 | Chapter 1: Strings
Using str_replace() for conversion, however, doesn’t respect tab stops. If you want
tab stops every eight characters, a line beginning with a five-letter word and a tab should
have that tab replaced with three spaces, not one. Use the tab_expand() function shown
in Example 1-22 to turn tabs to spaces in a way that respects tab stops.
Example 1-22. tab_expand( )
function tab_expand($text) {
while (strstr($text,"t")) {
$text = preg_replace_callback('/^([^tn]*)(t+)/m',
'tab_expand_helper', $text);
}
return $text;
}
function tab_expand_helper($matches) {
$tab_stop = 8;
return $matches[1] .
str_repeat(' ',strlen($matches[2]) *
$tab_stop - (strlen($matches[1]) % $tab_stop));
}
$spaced = tab_expand($obj->message);
You can use the tab_unexpand() function shown in Example 1-23 to turn spaces back
to tabs.
Example 1-23. tab_unexpand( )
function tab_unexpand($text) {
$tab_stop = 8;
$lines = explode("n",$text);
foreach ($lines as $i => $line) {
// Expand any tabs to spaces
$line = tab_expand($line);
$chunks = str_split($line, $tab_stop);
$chunkCount = count($chunks);
// Scan all but the last chunk
for ($j = 0; $j < $chunkCount - 1; $j++) {
$chunks[$j] = preg_replace('/ {2,}$/',"t",$chunks[$j]);
}
// If the last chunk is a tab-stop's worth of spaces
// convert it to a tab; Otherwise, leave it alone
if ($chunks[$chunkCount-1] == str_repeat(' ', $tab_stop)) {
$chunks[$chunkCount-1] = "t";
}
// Recombine the chunks
$lines[$i] = implode('',$chunks);
}
// Recombine the lines
1.7 Expanding and Compressing Tabs | 13
return implode("n",$lines);
}
$tabbed = tab_unexpand($obj->message);
Both functions take a string as an argument and return the string appropriately modi‐
fied.
Discussion
Each function assumes tab stops are every eight spaces, but that can be modified by
changing the setting of the $tab_stop variable.
The regular expression in tab_expand() matches both a group of tabs and all the text
in a line before that group of tabs. It needs to match the text before the tabs because the
length of that text affects how many spaces the tabs should be replaced with so that
subsequent text is aligned with the next tab stop. The function doesn’t just replace each
tab with eight spaces; it adjusts text after tabs to line up with tab stops.
Similarly, tab_unexpand() doesn’t just look for eight consecutive spaces and then re‐
place them with one tab character. It divides up each line into eight-character chunks
and then substitutes ending whitespace in those chunks (at least two spaces) with tabs.
This not only preserves text alignment with tab stops; it also saves space in the string.
See Also
Documentation on str_replace(), on preg_replace_callback(), and on
str_split(). Recipe 23.10 has more information on preg_replace_callback().
1.8 Controlling Case
Problem
You need to capitalize, lowercase, or otherwise modify the case of letters in a string. For
example, you want to capitalize the initial letters of names but lowercase the rest.
Solution
Use ucfirst() or ucwords() to capitalize the first letter of one or more words, as shown
in Example 1-24.
Example 1-24. Capitalizing letters
print ucfirst("how do you do today?");
print ucwords("the prince of wales");
14 | Chapter 1: Strings
Example 1-24 prints:
How do you do today?
The Prince Of Wales
Use strtolower() or strtoupper() to modify the case of entire strings, as in
Example 1-25.
Example 1-25. Changing case of strings
print strtoupper("i'm not yelling!");
print strtolower('<A HREF="one.php">one</A>');
Example 1-25 prints:
I'M NOT YELLING!
<a href="one.php">one</a>
Discussion
Use ucfirst() to capitalize the first character in a string:
print ucfirst('monkey face');
print ucfirst('1 monkey face');
This prints:
Monkey face
1 monkey face
Note that the second phrase is not “1 Monkey face.”
Use ucwords() to capitalize the first character of each word in a string:
print ucwords('1 monkey face');
print ucwords("don't play zone defense against the philadelphia 76-ers");
This prints:
1 Monkey Face
Don't Play Zone Defense Against The Philadelphia 76-ers
As expected, ucwords() doesn’t capitalize the “t” in “don’t.” But it also doesn’t capitalize
the “e” in “76-ers.” For ucwords(), a word is any sequence of nonwhitespace characters
that follows one or more whitespace characters. Because both ' and - aren’t whitespace
characters,ucwords() doesn’tconsiderthe“t”in“don’t”orthe“e”in“76-ers”tobeword-
starting characters.
Both ucfirst() and ucwords() don’t change the case of non–first letters:
print ucfirst('macWorld says I should get an iBook');
print ucwords('eTunaFish.com might buy itunaFish.Com!');
This prints:
1.8 Controlling Case | 15
MacWorld says I should get an iBook
ETunaFish.com Might Buy ItunaFish.Com!
The functions strtolower() and strtoupper() work on entire strings, not just indi‐
vidual characters. All alphabetic characters are changed to lowercase by strtolow
er() and strtoupper() changes all alphabetic characters to uppercase:
print strtolower("I programmed the WOPR and the TRS-80.");
print strtoupper('"since feeling is first" is a poem by e. e. cummings.');
This prints:
i programmed the wopr and the trs-80.
"SINCE FEELING IS FIRST" IS A POEM BY E. E. CUMMINGS.
When determining upper- and lowercase, these functions respect your locale settings.
See Also
For more information about locale settings, see Chapter 19; documentation on uc
first(), ucwords(), strtolower(), and strtoupper().
1.9 Interpolating Functions and Expressions Within
Strings
Problem
You want to include the results of executing a function or expression within a string.
Solution
Use the string concatenation operator (.), as shown in Example 1-26, when the value
you want to include can’t be inside the string.
Example 1-26. String concatenation
print 'You have '.($_POST['boys'] + $_POST['girls']).' children.';
print "The word '$word' is ".strlen($word).' characters long.';
print 'You owe '.$amounts['payment'].' immediately.';
print "My circle's diameter is ".$circle->getDiameter().' inches.';
Discussion
You can put variables, object properties, and array elements (if the subscript is unquo‐
ted) directly in double-quoted strings:
print "I have $children children.";
print "You owe $amounts[payment] immediately.";
print "My circle's diameter is $circle->diameter inches.";
16 | Chapter 1: Strings
Interpolation with double-quoted strings places some limitations on the syntax of what
can be interpolated. In the previous example, $amounts['payment'] had to be written
as $amounts[payment] so it would be interpolated properly. Use curly braces around
more complicated expressions to interpolate them into a string. For example:
print "I have {$children} children.";
print "You owe {$amounts['payment']} immediately.";
print "My circle's diameter is {$circle->getDiameter()} inches.";
Direct interpolation or using string concatenation also works with heredocs. Interpo‐
lating with string concatenation in heredocs can look a little strange because the closing
heredoc delimiter and the string concatenation operator have to be on separate lines:
print <<< END
Right now, the time is
END
. strftime('%c') . <<< END
but tomorrow it will be
END
. strftime('%c',time() + 86400);
Also, if you’re interpolating with heredocs, make sure to include appropriate spacing
for the whole string to appear properly. In the previous example, Right now, the time
is has to include a trailing space, and but tomorrow it will be has to include leading
and trailing spaces.
See Also
For the syntax to interpolate variable variables (such as ${"amount_$i"}), see
Recipe 5.4; documentation on the string concatenation operator.
1.10 Trimming Blanks from a String
Problem
You want to remove whitespace from the beginning or end of a string. For example, you
want to clean up user input before validating it.
Solution
Use ltrim(), rtrim(), or trim(). The ltrim() function removes whitespace from the
beginning of a string, rtrim() from the end of a string, and trim() from both the
beginning and end of a string:
$zipcode = trim($_GET['zipcode']);
$no_linefeed = rtrim($_GET['text']);
$name = ltrim($_GET['name']);
1.10 Trimming Blanks from a String | 17
Discussion
For these functions, whitespace is defined as the following characters: newline, carriage
return, space, horizontal and vertical tab, and null.
Trimming whitespace off of strings saves storage space and can make for more precise
display of formatted data or text within <pre> tags, for example. If you are doing com‐
parisonswithuserinput,youshouldtrimthedatafirst,sothatsomeonewhomistakenly
enters 98052 followed by a few spaces as their zip code isn’t forced to fix an error that
really isn’t one. Trimming before exact text comparisons also ensures that, for example,
“salamin” equals “salami.” It’s also a good idea to normalize string data by trimming it
before storing it in a database.
The trim() functions can also remove user-specified characters from strings. Pass the
characters you want to remove as a second argument. You can indicate a range of char‐
acters with two dots between the first and last characters in the range:
// Remove numerals and space from the beginning of the line
print ltrim('10 PRINT A$',' 0..9');
// Remove semicolon from the end of the line
print rtrim('SELECT * FROM turtles;',';');
This prints:
PRINT A$
SELECT * FROM turtles
PHP also provides chop() as an alias for rtrim(). However, you’re best off using
rtrim() instead because PHP’s chop() behaves differently than Perl’s chop() (which is
deprecated in favor of chomp(), anyway), and using it can confuse others when they
read your code.
See Also
Documentation on trim(), ltrim(), and rtrim().
1.11 Generating Comma-Separated Data
Problem
You want to format data as comma-separated values (CSV) so that it can be imported
by a spreadsheet or database.
Solution
Use the fputcsv() function to generate a CSV-formatted line from an array of data.
Example 1-27 writes the data in $sales into a file.
18 | Chapter 1: Strings
Example 1-27. Generating comma-separated data
$sales = array( array('Northeast','2005-01-01','2005-02-01',12.54),
array('Northwest','2005-01-01','2005-02-01',546.33),
array('Southeast','2005-01-01','2005-02-01',93.26),
array('Southwest','2005-01-01','2005-02-01',945.21),
array('All Regions','--','--',1597.34) );
$filename = './sales.csv';
$fh = fopen($filename,'w') or die("Can't open $filename");
foreach ($sales as $sales_line) {
if (fputcsv($fh, $sales_line) === false) {
die("Can't write CSV line");
}
}
fclose($fh) or die("Can't close $filename");
Discussion
To print the CSV-formatted data instead of writing it to a file, use the special output
stream php://output, as shown in Example 1-28.
Example 1-28. Printing comma-separated data
$sales = array( array('Northeast','2005-01-01','2005-02-01',12.54),
array('Northwest','2005-01-01','2005-02-01',546.33),
array('Southeast','2005-01-01','2005-02-01',93.26),
array('Southwest','2005-01-01','2005-02-01',945.21),
array('All Regions','--','--',1597.34) );
$fh = fopen('php://output','w');
foreach ($sales as $sales_line) {
if (fputcsv($fh, $sales_line) === false) {
die("Can't write CSV line");
}
}
fclose($fh);
To put the CSV-formatted data into a string instead of printing it or writing it to a file,
combine the technique in Example 1-28 with output buffering, as shown in
Example 1-29.
Example 1-29. Putting comma-separated data into a string
$sales = array( array('Northeast','2005-01-01','2005-02-01',12.54),
array('Northwest','2005-01-01','2005-02-01',546.33),
array('Southeast','2005-01-01','2005-02-01',93.26),
array('Southwest','2005-01-01','2005-02-01',945.21),
array('All Regions','--','--',1597.34) );
ob_start();
1.11 Generating Comma-Separated Data | 19
$fh = fopen('php://output','w') or die("Can't open php://output");
foreach ($sales as $sales_line) {
if (fputcsv($fh, $sales_line) === false) {
die("Can't write CSV line");
}
}
fclose($fh) or die("Can't close php://output");
$output = ob_get_contents();
ob_end_clean();
See Also
Documentation on fputcsv(); Recipe 8.13 has more information about output buffer‐
ing.
1.12 Parsing Comma-Separated Data
Problem
You have data in comma-separated values (CSV) format—for example, a file exported
from Excel or a database—and you want to extract the records and fields into a format
you can manipulate in PHP.
Solution
If the CSV data is in a file (or available via a URL), open the file with fopen() and read
in the data with fgetcsv(). Example 1-30 prints out CSV data in an HTML table.
Example 1-30. Reading CSV data from a file
$fp = fopen($filename,'r') or die("can't open file");
print "<table>n";
while($csv_line = fgetcsv($fp)) {
print '<tr>';
for ($i = 0, $j = count($csv_line); $i < $j; $i++) {
print '<td>'.htmlentities($csv_line[$i]).'</td>';
}
print "</tr>n";
}
print "</table>n";
fclose($fp) or die("can't close file");
Discussion
By default, fgetcsv() reads in an entire line of data. If your average line length is more
than 8,192 bytes, your program may run faster if you specify an explicit line length
instead of letting PHP figure it out. Do this by providing a second argument to
fgetcsv() that is a value larger than the maximum length of a line in your CSV file.
20 | Chapter 1: Strings
(Don’t forget to count the end-of-line whitespace.) If you pass a line length of 0, PHP
will use the default behavior.
You can pass fgetcsv() an optional third argument, a delimiter to use instead of a
comma (,). However, using a different delimiter somewhat defeats the purpose of CSV
as an easy way to exchange tabular data.
Don’t be tempted to bypass fgetcsv() and just read a line in and explode() on the
commas. CSV is more complicated than that so that it can deal with field values that
have, for example, literal commas in them that should not be treated as field delimiters.
Using fgetcsv() protects you and your code from subtle errors.
See Also
Documentation on fgetcsv().
1.13 Generating Fixed-Width Field Data Records
Problem
You need to format data records such that each field takes up a set amount of characters.
Solution
Use pack() with a format string that specifies a sequence of space-padded strings.
Example 1-31 transforms an array of data into fixed-width records.
Example 1-31. Generating fixed-width field data records
$books = array( array('Elmer Gantry', 'Sinclair Lewis', 1927),
array('The Scarlatti Inheritance','Robert Ludlum', 1971),
array('The Parsifal Mosaic','William Styron', 1979) );
foreach ($books as $book) {
print pack('A25A15A4', $book[0], $book[1], $book[2]) . "n";
}
Discussion
The format string A25A14A4 tells pack() to transform its subsequent arguments into a
25-character space-padded string, a 14-character space-padded string, and a 4-
character space-padded string. For space-padded fields in fixed-width records, pack()
provides a concise solution.
To pad fields with something other than a space, however, use substr() to ensure that
the field values aren’t too long and str_pad() to ensure that the field values aren’t too
1.13 Generating Fixed-Width Field Data Records | 21
short. Example 1-32 transforms an array of records into fixed-width records
with .-padded fields.
Example 1-32. Generating fixed-width field data records without pack( )
$books = array( array('Elmer Gantry', 'Sinclair Lewis', 1927),
array('The Scarlatti Inheritance','Robert Ludlum', 1971),
array('The Parsifal Mosaic','William Styron', 1979) );
foreach ($books as $book) {
$title = str_pad(substr($book[0], 0, 25), 25, '.');
$author = str_pad(substr($book[1], 0, 15), 15, '.');
$year = str_pad(substr($book[2], 0, 4), 4, '.');
print "$title$author$yearn";
}
See Also
Documentation on pack() and on str_pad(). Recipe 1.17 discusses pack() format
strings in more detail.
1.14 Parsing Fixed-Width Field Data Records
Problem
You need to break apart fixed-width records in strings.
Solution
Use substr() as shown in Example 1-33.
Example 1-33. Parsing fixed-width records with substr( )
$fp = fopen('fixed-width-records.txt','r',true) or die ("can't open file");
while ($s = fgets($fp,1024)) {
$fields[1] = substr($s,0,25); // first field: first 25 characters of the line
$fields[2] = substr($s,25,15); // second field: next 15 characters of the line
$fields[3] = substr($s,40,4); // third field: next 4 characters of the line
$fields = array_map('rtrim', $fields); // strip the trailing whitespace
// a function to do something with the fields
process_fields($fields);
}
fclose($fp) or die("can't close file");
Or unpack(), as shown in Example 1-34.
Example 1-34. Parsing fixed-width records with unpack( )
function fixed_width_unpack($format_string,$data) {
$r = array();
22 | Chapter 1: Strings
for ($i = 0, $j = count($data); $i < $j; $i++) {
$r[$i] = unpack($format_string,$data[$i]);
}
return $r;
}
Discussion
Data in which each field is allotted a fixed number of characters per line may look like
this list of books, titles, and publication dates:
$booklist=<<<END
Elmer Gantry Sinclair Lewis 1927
The Scarlatti InheritanceRobert Ludlum 1971
The Parsifal Mosaic Robert Ludlum 1982
Sophie's Choice William Styron 1979
END;
In each line, the title occupies the first 25 characters, the author’s name the next 15
characters, and the publication year the next 4 characters. Knowing those field widths,
you can easily use substr() to parse the fields into an array:
$books = explode("n",$booklist);
for($i = 0, $j = count($books); $i < $j; $i++) {
$book_array[$i]['title'] = substr($books[$i],0,25);
$book_array[$i]['author'] = substr($books[$i],25,15);
$book_array[$i]['publication_year'] = substr($books[$i],40,4);
}
Exploding $booklist into an array of lines makes the looping code the same whether
it’s operating over a string or a series of lines read in from a file.
The loop can be made more flexible by specifying the field names and widths in a
separate array that can be passed to a parsing function, as shown in the
fixed_width_substr() function in Example 1-35.
Example 1-35. fixed_width_substr( )
function fixed_width_substr($fields,$data) {
$r = array();
for ($i = 0, $j = count($data); $i < $j; $i++) {
$line_pos = 0;
foreach($fields as $field_name => $field_length) {
$r[$i][$field_name] = rtrim(substr($data[$i],$line_pos,$field_length));
$line_pos += $field_length;
}
}
return $r;
}
$book_fields = array('title' => 25,
1.14 Parsing Fixed-Width Field Data Records | 23
'author' => 15,
'publication_year' => 4);
$book_array = fixed_width_substr($book_fields,$booklist);
The variable $line_pos keeps track of the start of each field and is advanced by the
previous field’s width as the code moves through each line. Use rtrim() to remove
trailing whitespace from each field.
You can use unpack() as a substitute for substr() to extract fields. Instead of specifying
the field names and widths as an associative array, create a format string for unpack().
A fixed-width field extractor using unpack() looks like the fixed_width_unpack()
function shown in Example 1-36.
Example 1-36. fixed_width_unpack( )
function fixed_width_unpack($format_string,$data) {
$r = array();
for ($i = 0, $j = count($data); $i < $j; $i++) {
$r[$i] = unpack($format_string,$data[$i]);
}
return $r;
}
BecausetheA formattounpack() meansspace-padded string,there’snoneedtortrim()
off the trailing spaces.
Once the fields have been parsed into $book_array by either function, the data can be
printed as an HTML table, for example:
$book_array = fixed_width_unpack('A25title/A15author/A4publication_year',
$books);
print "<table>n";
// print a header row
print '<tr><td>';
print join('</td><td>',array_keys($book_array[0]));
print "</td></tr>n";
// print each data row
foreach ($book_array as $row) {
print '<tr><td>';
print join('</td><td>',array_values($row));
print "</td></tr>n";
}
print "</table>n";
Joining data on </td><td> produces a table row that is missing its first <td> and last
</td>. We produce a complete table row by printing out <tr><td> before the joined
data and </td></tr> after the joined data.
24 | Chapter 1: Strings
Both substr() and unpack() have equivalent capabilities when the fixed-width fields
are strings, but unpack() is the better solution when the elements of the fields aren’t just
strings.
If all of your fields are the same size, str_split() is a handy shortcut for chopping up
incoming data. It returns an array made up of sections of a string. Example 1-37 uses
str_split() to break apart a string into 32-byte pieces.
Example 1-37. Chopping up a string with str_split( )
$fields = str_split($line_of_data,32);
// $fields[0] is bytes 0 - 31
// $fields[1] is bytes 32 - 63
// and so on
See Also
For more information about unpack(), see Recipe 1.17 and the PHP website; docu‐
mentation on str_split(); Recipe 4.8 discusses join().
1.15 Taking Strings Apart
Problem
You need to break a string into pieces. For example, you want to access each line that a
user enters in a <textarea> form field.
Solution
Use explode() if what separates the pieces is a constant string:
$words = explode(' ','My sentence is not very complicated');
Use preg_split() if you need a Perl-compatible regular expression to describe the
separator:
$words = preg_split('/d. /','my day: 1. get up 2. get dressed 3. eat toast');
$lines = preg_split('/[nr]+/',$_POST['textarea']);
Use the /i flag to preg_split() for case-insensitive separator matching:
$words = preg_split('/ x /i','31 inches x 22 inches X 9 inches');
Discussion
The simplest solution of the bunch is explode(). Pass it your separator string, the string
to be separated, and an optional limit on how many elements should be returned:
1.15 Taking Strings Apart | 25
$dwarves = 'dopey,sleepy,happy,grumpy,sneezy,bashful,doc';
$dwarf_array = explode(',',$dwarves);
This makes $dwarf_array a seven-element array, so print_r($dwarf_array) prints:
Array
(
[0] => dopey
[1] => sleepy
[2] => happy
[3] => grumpy
[4] => sneezy
[5] => bashful
[6] => doc
)
If the specified limit is less than the number of possible chunks, the last chunk contains
the remainder:
$dwarf_array = explode(',',$dwarves,5);
print_r($dwarf_array);
This prints:
Array
(
[0] => dopey
[1] => sleepy
[2] => happy
[3] => grumpy
[4] => sneezy,bashful,doc
)
The separator is treated literally by explode(). If you specify a comma and a space as a
separator, it breaks the string only on a comma followed by a space, not on a comma or
a space.
With preg_split(), you have more flexibility. Instead of a string literal as a separator,
it uses a Perl-compatible regular expression engine. With preg_split(), you can take
advantage of various Perl-ish regular expression extensions, as well as tricks such as
including the separator text in the returned array of strings:
$math = "3 + 2 / 7 - 9";
$stack = preg_split('/ *([+-/*]) */',$math,-1,PREG_SPLIT_DELIM_CAPTURE);
print_r($stack);
This prints:
Array
(
[0] => 3
[1] => +
[2] => 2
[3] => /
26 | Chapter 1: Strings
Another Random Document on
Scribd Without Any Related Topics
This eBook is for the use of anyone anywhere in the United
States and most other parts of the world at no cost and with
almost no restrictions whatsoever. You may copy it, give it away
or re-use it under the terms of the Project Gutenberg License
included with this eBook or online at www.gutenberg.org. If you
are not located in the United States, you will have to check the
laws of the country where you are located before using this
eBook.
1.E.2. If an individual Project Gutenberg™ electronic work is derived
from texts not protected by U.S. copyright law (does not contain a
notice indicating that it is posted with permission of the copyright
holder), the work can be copied and distributed to anyone in the
United States without paying any fees or charges. If you are
redistributing or providing access to a work with the phrase “Project
Gutenberg” associated with or appearing on the work, you must
comply either with the requirements of paragraphs 1.E.1 through
1.E.7 or obtain permission for the use of the work and the Project
Gutenberg™ trademark as set forth in paragraphs 1.E.8 or 1.E.9.
1.E.3. If an individual Project Gutenberg™ electronic work is posted
with the permission of the copyright holder, your use and distribution
must comply with both paragraphs 1.E.1 through 1.E.7 and any
additional terms imposed by the copyright holder. Additional terms
will be linked to the Project Gutenberg™ License for all works posted
with the permission of the copyright holder found at the beginning
of this work.
1.E.4. Do not unlink or detach or remove the full Project
Gutenberg™ License terms from this work, or any files containing a
part of this work or any other work associated with Project
Gutenberg™.
1.E.5. Do not copy, display, perform, distribute or redistribute this
electronic work, or any part of this electronic work, without
prominently displaying the sentence set forth in paragraph 1.E.1
with active links or immediate access to the full terms of the Project
Gutenberg™ License.
1.E.6. You may convert to and distribute this work in any binary,
compressed, marked up, nonproprietary or proprietary form,
including any word processing or hypertext form. However, if you
provide access to or distribute copies of a Project Gutenberg™ work
in a format other than “Plain Vanilla ASCII” or other format used in
the official version posted on the official Project Gutenberg™ website
(www.gutenberg.org), you must, at no additional cost, fee or
expense to the user, provide a copy, a means of exporting a copy, or
a means of obtaining a copy upon request, of the work in its original
“Plain Vanilla ASCII” or other form. Any alternate format must
include the full Project Gutenberg™ License as specified in
paragraph 1.E.1.
1.E.7. Do not charge a fee for access to, viewing, displaying,
performing, copying or distributing any Project Gutenberg™ works
unless you comply with paragraph 1.E.8 or 1.E.9.
1.E.8. You may charge a reasonable fee for copies of or providing
access to or distributing Project Gutenberg™ electronic works
provided that:
• You pay a royalty fee of 20% of the gross profits you derive
from the use of Project Gutenberg™ works calculated using the
method you already use to calculate your applicable taxes. The
fee is owed to the owner of the Project Gutenberg™ trademark,
but he has agreed to donate royalties under this paragraph to
the Project Gutenberg Literary Archive Foundation. Royalty
payments must be paid within 60 days following each date on
which you prepare (or are legally required to prepare) your
periodic tax returns. Royalty payments should be clearly marked
as such and sent to the Project Gutenberg Literary Archive
Foundation at the address specified in Section 4, “Information
about donations to the Project Gutenberg Literary Archive
Foundation.”
• You provide a full refund of any money paid by a user who
notifies you in writing (or by e-mail) within 30 days of receipt
that s/he does not agree to the terms of the full Project
Gutenberg™ License. You must require such a user to return or
destroy all copies of the works possessed in a physical medium
and discontinue all use of and all access to other copies of
Project Gutenberg™ works.
• You provide, in accordance with paragraph 1.F.3, a full refund of
any money paid for a work or a replacement copy, if a defect in
the electronic work is discovered and reported to you within 90
days of receipt of the work.
• You comply with all other terms of this agreement for free
distribution of Project Gutenberg™ works.
1.E.9. If you wish to charge a fee or distribute a Project Gutenberg™
electronic work or group of works on different terms than are set
forth in this agreement, you must obtain permission in writing from
the Project Gutenberg Literary Archive Foundation, the manager of
the Project Gutenberg™ trademark. Contact the Foundation as set
forth in Section 3 below.
1.F.
1.F.1. Project Gutenberg volunteers and employees expend
considerable effort to identify, do copyright research on, transcribe
and proofread works not protected by U.S. copyright law in creating
the Project Gutenberg™ collection. Despite these efforts, Project
Gutenberg™ electronic works, and the medium on which they may
be stored, may contain “Defects,” such as, but not limited to,
incomplete, inaccurate or corrupt data, transcription errors, a
copyright or other intellectual property infringement, a defective or
damaged disk or other medium, a computer virus, or computer
codes that damage or cannot be read by your equipment.
1.F.2. LIMITED WARRANTY, DISCLAIMER OF DAMAGES - Except for
the “Right of Replacement or Refund” described in paragraph 1.F.3,
the Project Gutenberg Literary Archive Foundation, the owner of the
Project Gutenberg™ trademark, and any other party distributing a
Project Gutenberg™ electronic work under this agreement, disclaim
all liability to you for damages, costs and expenses, including legal
fees. YOU AGREE THAT YOU HAVE NO REMEDIES FOR
NEGLIGENCE, STRICT LIABILITY, BREACH OF WARRANTY OR
BREACH OF CONTRACT EXCEPT THOSE PROVIDED IN PARAGRAPH
1.F.3. YOU AGREE THAT THE FOUNDATION, THE TRADEMARK
OWNER, AND ANY DISTRIBUTOR UNDER THIS AGREEMENT WILL
NOT BE LIABLE TO YOU FOR ACTUAL, DIRECT, INDIRECT,
CONSEQUENTIAL, PUNITIVE OR INCIDENTAL DAMAGES EVEN IF
YOU GIVE NOTICE OF THE POSSIBILITY OF SUCH DAMAGE.
1.F.3. LIMITED RIGHT OF REPLACEMENT OR REFUND - If you
discover a defect in this electronic work within 90 days of receiving
it, you can receive a refund of the money (if any) you paid for it by
sending a written explanation to the person you received the work
from. If you received the work on a physical medium, you must
return the medium with your written explanation. The person or
entity that provided you with the defective work may elect to provide
a replacement copy in lieu of a refund. If you received the work
electronically, the person or entity providing it to you may choose to
give you a second opportunity to receive the work electronically in
lieu of a refund. If the second copy is also defective, you may
demand a refund in writing without further opportunities to fix the
problem.
1.F.4. Except for the limited right of replacement or refund set forth
in paragraph 1.F.3, this work is provided to you ‘AS-IS’, WITH NO
OTHER WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO WARRANTIES OF
MERCHANTABILITY OR FITNESS FOR ANY PURPOSE.
1.F.5. Some states do not allow disclaimers of certain implied
warranties or the exclusion or limitation of certain types of damages.
If any disclaimer or limitation set forth in this agreement violates the
law of the state applicable to this agreement, the agreement shall be
interpreted to make the maximum disclaimer or limitation permitted
by the applicable state law. The invalidity or unenforceability of any
provision of this agreement shall not void the remaining provisions.
1.F.6. INDEMNITY - You agree to indemnify and hold the Foundation,
the trademark owner, any agent or employee of the Foundation,
anyone providing copies of Project Gutenberg™ electronic works in
accordance with this agreement, and any volunteers associated with
the production, promotion and distribution of Project Gutenberg™
electronic works, harmless from all liability, costs and expenses,
including legal fees, that arise directly or indirectly from any of the
following which you do or cause to occur: (a) distribution of this or
any Project Gutenberg™ work, (b) alteration, modification, or
additions or deletions to any Project Gutenberg™ work, and (c) any
Defect you cause.
Section 2. Information about the Mission
of Project Gutenberg™
Project Gutenberg™ is synonymous with the free distribution of
electronic works in formats readable by the widest variety of
computers including obsolete, old, middle-aged and new computers.
It exists because of the efforts of hundreds of volunteers and
donations from people in all walks of life.
Volunteers and financial support to provide volunteers with the
assistance they need are critical to reaching Project Gutenberg™’s
goals and ensuring that the Project Gutenberg™ collection will
remain freely available for generations to come. In 2001, the Project
Gutenberg Literary Archive Foundation was created to provide a
secure and permanent future for Project Gutenberg™ and future
generations. To learn more about the Project Gutenberg Literary
Archive Foundation and how your efforts and donations can help,
see Sections 3 and 4 and the Foundation information page at
www.gutenberg.org.
Section 3. Information about the Project
Gutenberg Literary Archive Foundation
The Project Gutenberg Literary Archive Foundation is a non-profit
501(c)(3) educational corporation organized under the laws of the
state of Mississippi and granted tax exempt status by the Internal
Revenue Service. The Foundation’s EIN or federal tax identification
number is 64-6221541. Contributions to the Project Gutenberg
Literary Archive Foundation are tax deductible to the full extent
permitted by U.S. federal laws and your state’s laws.
The Foundation’s business office is located at 809 North 1500 West,
Salt Lake City, UT 84116, (801) 596-1887. Email contact links and up
to date contact information can be found at the Foundation’s website
and official page at www.gutenberg.org/contact
Section 4. Information about Donations to
the Project Gutenberg Literary Archive
Foundation
Project Gutenberg™ depends upon and cannot survive without
widespread public support and donations to carry out its mission of
increasing the number of public domain and licensed works that can
be freely distributed in machine-readable form accessible by the
widest array of equipment including outdated equipment. Many
small donations ($1 to $5,000) are particularly important to
maintaining tax exempt status with the IRS.
The Foundation is committed to complying with the laws regulating
charities and charitable donations in all 50 states of the United
States. Compliance requirements are not uniform and it takes a
considerable effort, much paperwork and many fees to meet and
keep up with these requirements. We do not solicit donations in
locations where we have not received written confirmation of
compliance. To SEND DONATIONS or determine the status of
compliance for any particular state visit www.gutenberg.org/donate.
While we cannot and do not solicit contributions from states where
we have not met the solicitation requirements, we know of no
prohibition against accepting unsolicited donations from donors in
such states who approach us with offers to donate.
International donations are gratefully accepted, but we cannot make
any statements concerning tax treatment of donations received from
outside the United States. U.S. laws alone swamp our small staff.
Please check the Project Gutenberg web pages for current donation
methods and addresses. Donations are accepted in a number of
other ways including checks, online payments and credit card
donations. To donate, please visit: www.gutenberg.org/donate.
Section 5. General Information About
Project Gutenberg™ electronic works
Professor Michael S. Hart was the originator of the Project
Gutenberg™ concept of a library of electronic works that could be
freely shared with anyone. For forty years, he produced and
distributed Project Gutenberg™ eBooks with only a loose network of
volunteer support.
Project Gutenberg™ eBooks are often created from several printed
editions, all of which are confirmed as not protected by copyright in
the U.S. unless a copyright notice is included. Thus, we do not
necessarily keep eBooks in compliance with any particular paper
edition.
Most people start at our website which has the main PG search
facility: www.gutenberg.org.
This website includes information about Project Gutenberg™,
including how to make donations to the Project Gutenberg Literary
Archive Foundation, how to help produce our new eBooks, and how
to subscribe to our email newsletter to hear about new eBooks.
Welcome to our website – the perfect destination for book lovers and
knowledge seekers. We believe that every book holds a new world,
offering opportunities for learning, discovery, and personal growth.
That’s why we are dedicated to bringing you a diverse collection of
books, ranging from classic literature and specialized publications to
self-development guides and children's books.
More than just a book-buying platform, we strive to be a bridge
connecting you with timeless cultural and intellectual values. With an
elegant, user-friendly interface and a smart search system, you can
quickly find the books that best suit your interests. Additionally,
our special promotions and home delivery services help you save time
and fully enjoy the joy of reading.
Join us on a journey of knowledge exploration, passion nurturing, and
personal growth every day!
ebookbell.com

More Related Content

PDF
Python CookBook 3rd ed learn bout the programming .pdf
PDF
PDF
Ruby Cookbook Recipes For Objectoriented Scripting 2nd Edition Carlson
PDF
Python Cookbook Third Edition 3rd Edition David Beazley Brian Jones
PDF
Algorithmic Problem Solving with Python.pdf
PDF
PythonIntro
PDF
Javanotes6 linked
PDF
Python for Everybody
Python CookBook 3rd ed learn bout the programming .pdf
Ruby Cookbook Recipes For Objectoriented Scripting 2nd Edition Carlson
Python Cookbook Third Edition 3rd Edition David Beazley Brian Jones
Algorithmic Problem Solving with Python.pdf
PythonIntro
Javanotes6 linked
Python for Everybody

Similar to Php Cookbook Solutions Examples For Php Programmers 3rd David Sklar Adam Trachtenberg (20)

PDF
Perl 5 guide
PDF
Perl tut
PDF
perltut
PDF
Perl &lt;b>5 Tutorial&lt;/b>, First Edition
PDF
perltut
PDF
&lt;img src="../i/r_14.png" />
PDF
An Introduction to Computer Science - python
PDF
Python for everybody
PDF
Introduction to Programming Using Java v. 7 - David J Eck - Inglês
PDF
python learn basic tutorial learn easy..
PDF
Practical Programming.pdf
PDF
thinkcspy3.pdf
PDF
Javanotes5 linked
PDF
Francois fleuret -_c++_lecture_notes
PDF
pickingUpPerl
PDF
pickingUpPerl
PDF
tutorial.pdf
PDF
Python for informatics
PDF
PDF
Learn python the right way
Perl 5 guide
Perl tut
perltut
Perl &lt;b>5 Tutorial&lt;/b>, First Edition
perltut
&lt;img src="../i/r_14.png" />
An Introduction to Computer Science - python
Python for everybody
Introduction to Programming Using Java v. 7 - David J Eck - Inglês
python learn basic tutorial learn easy..
Practical Programming.pdf
thinkcspy3.pdf
Javanotes5 linked
Francois fleuret -_c++_lecture_notes
pickingUpPerl
pickingUpPerl
tutorial.pdf
Python for informatics
Learn python the right way
Ad

Recently uploaded (20)

PDF
BÀI TẬP BỔ TRỢ 4 KỸ NĂNG TIẾNG ANH 9 GLOBAL SUCCESS - CẢ NĂM - BÁM SÁT FORM Đ...
PPTX
The Healthy Child – Unit II | Child Health Nursing I | B.Sc Nursing 5th Semester
PDF
FourierSeries-QuestionsWithAnswers(Part-A).pdf
PDF
Origin of periodic table-Mendeleev’s Periodic-Modern Periodic table
PDF
Basic Mud Logging Guide for educational purpose
PDF
Business Ethics Teaching Materials for college
PPTX
Week 4 Term 3 Study Techniques revisited.pptx
PPTX
Introduction to Child Health Nursing – Unit I | Child Health Nursing I | B.Sc...
PDF
Complications of Minimal Access Surgery at WLH
PDF
TR - Agricultural Crops Production NC III.pdf
PPTX
IMMUNITY IMMUNITY refers to protection against infection, and the immune syst...
PDF
Mark Klimek Lecture Notes_240423 revision books _173037.pdf
PDF
Pre independence Education in Inndia.pdf
PPTX
PPH.pptx obstetrics and gynecology in nursing
PPTX
Microbial diseases, their pathogenesis and prophylaxis
PDF
The Lost Whites of Pakistan by Jahanzaib Mughal.pdf
PDF
3rd Neelam Sanjeevareddy Memorial Lecture.pdf
PDF
Supply Chain Operations Speaking Notes -ICLT Program
PPTX
Renaissance Architecture: A Journey from Faith to Humanism
PDF
ANTIBIOTICS.pptx.pdf………………… xxxxxxxxxxxxx
BÀI TẬP BỔ TRỢ 4 KỸ NĂNG TIẾNG ANH 9 GLOBAL SUCCESS - CẢ NĂM - BÁM SÁT FORM Đ...
The Healthy Child – Unit II | Child Health Nursing I | B.Sc Nursing 5th Semester
FourierSeries-QuestionsWithAnswers(Part-A).pdf
Origin of periodic table-Mendeleev’s Periodic-Modern Periodic table
Basic Mud Logging Guide for educational purpose
Business Ethics Teaching Materials for college
Week 4 Term 3 Study Techniques revisited.pptx
Introduction to Child Health Nursing – Unit I | Child Health Nursing I | B.Sc...
Complications of Minimal Access Surgery at WLH
TR - Agricultural Crops Production NC III.pdf
IMMUNITY IMMUNITY refers to protection against infection, and the immune syst...
Mark Klimek Lecture Notes_240423 revision books _173037.pdf
Pre independence Education in Inndia.pdf
PPH.pptx obstetrics and gynecology in nursing
Microbial diseases, their pathogenesis and prophylaxis
The Lost Whites of Pakistan by Jahanzaib Mughal.pdf
3rd Neelam Sanjeevareddy Memorial Lecture.pdf
Supply Chain Operations Speaking Notes -ICLT Program
Renaissance Architecture: A Journey from Faith to Humanism
ANTIBIOTICS.pptx.pdf………………… xxxxxxxxxxxxx
Ad

Php Cookbook Solutions Examples For Php Programmers 3rd David Sklar Adam Trachtenberg

  • 1. Php Cookbook Solutions Examples For Php Programmers 3rd David Sklar Adam Trachtenberg download https://ebookbell.com/product/php-cookbook-solutions-examples- for-php-programmers-3rd-david-sklar-adam-trachtenberg-4748850 Explore and download more ebooks at ebookbell.com
  • 2. Here are some recommended products that we believe you will be interested in. You can click the link to download. Php Cookbook Modern Code Solutions For Professional Developers 1st Edition Eric A Mann https://ebookbell.com/product/php-cookbook-modern-code-solutions-for- professional-developers-1st-edition-eric-a-mann-53559800 Php Cookbook 2nd Edition David Sklar Adam Trachtenberg https://ebookbell.com/product/php-cookbook-2nd-edition-david-sklar- adam-trachtenberg-2244940 Php Cookbook Third Early Release 20220713 Third Early Release Eric A Mann https://ebookbell.com/product/php-cookbook-third-early- release-20220713-third-early-release-eric-a-mann-43887496 Php Cookbook 1st Edition David Sklar Adam Trachtenberg https://ebookbell.com/product/php-cookbook-1st-edition-david-sklar- adam-trachtenberg-1213864
  • 3. Php Cookbook Eric A Mann https://ebookbell.com/product/php-cookbook-eric-a-mann-232273274 Php Ajax Cookbook Milan Sedliak Rajesh Jeba R Anbiah Roshan Bhattarai https://ebookbell.com/product/php-ajax-cookbook-milan-sedliak-rajesh- jeba-r-anbiah-roshan-bhattarai-2490048 Php Jquery Cookbook Vijay Joshi https://ebookbell.com/product/php-jquery-cookbook-vijay-joshi-2531248 Php Ajax Cookbook Code For Book Sedliak M Anbiah Rrj Bhattarai R https://ebookbell.com/product/php-ajax-cookbook-code-for-book-sedliak- m-anbiah-rrj-bhattarai-r-6318474 Php 7 Programming Cookbook Doug Bierer https://ebookbell.com/product/php-7-programming-cookbook-doug- bierer-6808568
  • 7. David Sklar and Adam Trachtenberg THIRD EDITION PHP Cookbook
  • 8. PHP Cookbook, Third Edition by David Sklar and Adam Trachtenberg Copyright © 2014 David Sklar and Adam Trachtenberg. All rights reserved. Printed in the United States of America. Published by O’Reilly Media, Inc., 1005 Gravenstein Highway North, Sebastopol, CA 95472. O’Reilly books may be purchased for educational, business, or sales promotional use. Online editions are alsoavailableformosttitles(http://my.safaribooksonline.com).Formoreinformation,contactourcorporate/ institutional sales department: 800-998-9938 or corporate@oreilly.com. Editors:Rachel Roumeliotis and Allyson MacDonald Production Editor: Melanie Yarbrough Copyeditor: Kim Cofer Proofreader: Charles Roumeliotis Indexer: Judith McConville Cover Designer: Karen Montgomery Interior Designer: David Futato Illustrator: Rebecca Demarest June 2001: First Edition June 2004: Second Edition June 2014: Third Edition Revision History for the Third Edition: 2014-06-25: First release See http://oreilly.com/catalog/errata.csp?isbn=9781449363758 for release details. Nutshell Handbook, the Nutshell Handbook logo, and the O’Reilly logo are registered trademarks of O’Reilly Media, Inc. PHP Cookbook, the image of a Galapagos land iguana, and related trade dress are trademarks of O’Reilly Media, Inc. Many of the designations used by manufacturers and sellers to distinguish their products are claimed as trademarks.Wherethosedesignationsappearinthisbook,andO’ReillyMedia,Inc.wasawareofatrademark claim, the designations have been printed in caps or initial caps. While every precaution has been taken in the preparation of this book, the publisher and authors assume no responsibility for errors or omissions, or for damages resulting from the use of the information contained herein. ISBN: 978-1-449-36375-8 [LSI]
  • 9. Table of Contents Preface. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xv 1. Strings. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 1.1 Accessing Substrings 5 1.2 Extracting Substrings 6 1.3 Replacing Substrings 7 1.4 Processing a String One Byte at a Time 9 1.5 Reversing a String by Word or Byte 10 1.6 Generating a Random String 11 1.7 Expanding and Compressing Tabs 12 1.8 Controlling Case 14 1.9 Interpolating Functions and Expressions Within Strings 16 1.10 Trimming Blanks from a String 17 1.11 Generating Comma-Separated Data 18 1.12 Parsing Comma-Separated Data 20 1.13 Generating Fixed-Width Field Data Records 21 1.14 Parsing Fixed-Width Field Data Records 22 1.15 Taking Strings Apart 25 1.16 Wrapping Text at a Certain Line Length 27 1.17 Storing Binary Data in Strings 28 1.18 Program: Downloadable CSV File 31 2. Numbers. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 2.1 Checking Whether a Variable Contains a Valid Number 36 2.2 Comparing Floating-Point Numbers 37 2.3 Rounding Floating-Point Numbers 38 2.4 Operating on a Series of Integers 40 2.5 Generating Random Numbers Within a Range 42 2.6 Generating Predictable Random Numbers 43 iii
  • 10. 2.7 Generating Biased Random Numbers 44 2.8 Taking Logarithms 46 2.9 Calculating Exponents 46 2.10 Formatting Numbers 47 2.11 Formatting Monetary Values 49 2.12 Printing Correct Plurals 50 2.13 Calculating Trigonometric Functions 51 2.14 Doing Trigonometry in Degrees, Not Radians 52 2.15 Handling Very Large or Very Small Numbers 53 2.16 Converting Between Bases 55 2.17 Calculating Using Numbers in Bases Other Than Decimal 56 2.18 Finding the Distance Between Two Places 58 3. Dates and Times. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61 3.1 Finding the Current Date and Time 63 3.2 Converting Time and Date Parts to an Epoch Timestamp 66 3.3 Converting an Epoch Timestamp to Time and Date Parts 68 3.4 Printing a Date or Time in a Specified Format 69 3.5 Finding the Difference of Two Dates 71 3.6 Finding the Day in a Week, Month, or Year 73 3.7 Validating a Date 75 3.8 Parsing Dates and Times from Strings 77 3.9 Adding to or Subtracting from a Date 79 3.10 Calculating Time with Time Zones and Daylight Saving Time 80 3.11 Generating a High-Precision Time 82 3.12 Generating Time Ranges 83 3.13 Using Non-Gregorian Calendars 84 3.14 Program: Calendar 87 4. Arrays. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93 4.1 Specifying an Array Not Beginning at Element 0 96 4.2 Storing Multiple Elements per Key in an Array 97 4.3 Initializing an Array to a Range of Integers 99 4.4 Iterating Through an Array 99 4.5 Deleting Elements from an Array 102 4.6 Changing Array Size 104 4.7 Appending One Array to Another 106 4.8 Turning an Array into a String 108 4.9 Printing an Array with Commas 109 4.10 Checking if a Key Is in an Array 110 4.11 Checking if an Element Is in an Array 111 4.12 Finding the Position of a Value in an Array 113 iv | Table of Contents
  • 11. 4.13 Finding Elements That Pass a Certain Test 114 4.14 Finding the Largest or Smallest Valued Element in an Array 115 4.15 Reversing an Array 116 4.16 Sorting an Array 116 4.17 Sorting an Array by a Computable Field 118 4.18 Sorting Multiple Arrays 120 4.19 Sorting an Array Using a Method Instead of a Function 122 4.20 Randomizing an Array 123 4.21 Removing Duplicate Elements from an Array 123 4.22 Applying a Function to Each Element in an Array 124 4.23 Finding the Union, Intersection, or Difference of Two Arrays 126 4.24 Iterating Efficiently over Large or Expensive Datasets 128 4.25 Accessing an Object Using Array Syntax 131 5. Variables. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135 5.1 Avoiding == Versus = Confusion 137 5.2 Establishing a Default Value 138 5.3 Exchanging Values Without Using Temporary Variables 139 5.4 Creating a Dynamic Variable Name 140 5.5 Persisting a Local Variable’s Value Across Function Invocations 141 5.6 Sharing Variables Between Processes 143 5.7 Encapsulating Complex Data Types in a String 149 5.8 Dumping Variable Contents as Strings 151 6. Functions. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157 6.1 Accessing Function Parameters 158 6.2 Setting Default Values for Function Parameters 159 6.3 Passing Values by Reference 161 6.4 Using Named Parameters 162 6.5 Enforcing Types of Function Arguments 163 6.6 Creating Functions That Take a Variable Number of Arguments 164 6.7 Returning Values by Reference 167 6.8 Returning More Than One Value 169 6.9 Skipping Selected Return Values 170 6.10 Returning Failure 171 6.11 Calling Variable Functions 172 6.12 Accessing a Global Variable Inside a Function 175 6.13 Creating Dynamic Functions 176 7. Classes and Objects. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179 7.1 Instantiating Objects 183 7.2 Defining Object Constructors 184 Table of Contents | v
  • 12. 7.3 Defining Object Destructors 185 7.4 Implementing Access Control 186 7.5 Preventing Changes to Classes and Methods 189 7.6 Defining Object Stringification 190 7.7 Requiring Multiple Classes to Behave Similarly 191 7.8 Creating Abstract Base Classes 195 7.9 Assigning Object References 197 7.10 Cloning Objects 198 7.11 Overriding Property Accesses 201 7.12 Calling Methods on an Object Returned by Another Method 205 7.13 Aggregating Objects 206 7.14 Accessing Overridden Methods 210 7.15 Creating Methods Dynamically 212 7.16 Using Method Polymorphism 213 7.17 Defining Class Constants 215 7.18 Defining Static Properties and Methods 217 7.19 Controlling Object Serialization 220 7.20 Introspecting Objects 222 7.21 Checking If an Object Is an Instance of a Specific Class 226 7.22 Autoloading Class Files upon Object Instantiation 229 7.23 Instantiating an Object Dynamically 230 7.24 Program: whereis 231 8. Web Fundamentals. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235 8.1 Setting Cookies 236 8.2 Reading Cookie Values 238 8.3 Deleting Cookies 238 8.4 Building a Query String 239 8.5 Reading the POST Request Body 240 8.6 Using HTTP Basic or Digest Authentication 241 8.7 Using Cookie Authentication 245 8.8 Reading an HTTP Header 248 8.9 Writing an HTTP Header 249 8.10 Sending a Specific HTTP Status Code 250 8.11 Redirecting to a Different Location 251 8.12 Flushing Output to the Browser 252 8.13 Buffering Output to the Browser 253 8.14 Compressing Web Output 255 8.15 Reading Environment Variables 255 8.16 Setting Environment Variables 256 8.17 Communicating Within Apache 257 8.18 Redirecting Mobile Browsers to a Mobile Optimized Site 258 vi | Table of Contents
  • 13. 8.19 Program: Website Account (De)activator 259 8.20 Program: Tiny Wiki 262 8.21 Program: HTTP Range 265 9. Forms. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275 9.1 Processing Form Input 277 9.2 Validating Form Input: Required Fields 279 9.3 Validating Form Input: Numbers 281 9.4 Validating Form Input: Email Addresses 283 9.5 Validating Form Input: Drop-Down Menus 284 9.6 Validating Form Input: Radio Buttons 285 9.7 Validating Form Input: Checkboxes 287 9.8 Validating Form Input: Dates and Times 289 9.9 Validating Form Input: Credit Cards 290 9.10 Preventing Cross-Site Scripting 291 9.11 Processing Uploaded Files 292 9.12 Working with Multipage Forms 295 9.13 Redisplaying Forms with Inline Error Messages 296 9.14 Guarding Against Multiple Submissions of the Same Form 299 9.15 Preventing Global Variable Injection 301 9.16 Handling Remote Variables with Periods in Their Names 303 9.17 Using Form Elements with Multiple Options 304 9.18 Creating Drop-Down Menus Based on the Current Date 305 10. Database Access. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307 10.1 Using DBM Databases 310 10.2 Using an SQLite Database 313 10.3 Connecting to an SQL Database 315 10.4 Querying an SQL Database 316 10.5 Retrieving Rows Without a Loop 319 10.6 Modifying Data in an SQL Database 320 10.7 Repeating Queries Efficiently 321 10.8 Finding the Number of Rows Returned by a Query 324 10.9 Escaping Quotes 325 10.10 Logging Debugging Information and Errors 327 10.11 Creating Unique Identifiers 329 10.12 Building Queries Programmatically 331 10.13 Making Paginated Links for a Series of Records 336 10.14 Caching Queries and Results 339 10.15 Accessing a Database Connection Anywhere in Your Program 341 10.16 Program: Storing a Threaded Message Board 343 Table of Contents | vii
  • 14. 10.17 Using Redis 351 11. Sessions and Data Persistence. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 353 11.1 Using Session Tracking 354 11.2 Preventing Session Hijacking 356 11.3 Preventing Session Fixation 357 11.4 Storing Sessons in Memcached 358 11.5 Storing Sessions in a Database 359 11.6 Storing Arbitrary Data in Shared Memory 362 11.7 Caching Calculated Results in Summary Tables 365 12. XML. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 369 12.1 Generating XML as a String 372 12.2 Generating XML with DOM 373 12.3 Parsing Basic XML Documents 376 12.4 Parsing Complex XML Documents 379 12.5 Parsing Large XML Documents 381 12.6 Extracting Information Using XPath 387 12.7 Transforming XML with XSLT 390 12.8 Setting XSLT Parameters from PHP 392 12.9 Calling PHP Functions from XSLT Stylesheets 394 12.10 Validating XML Documents 398 12.11 Handling Content Encoding 400 12.12 Reading RSS and Atom Feeds 401 12.13 Writing RSS Feeds 404 12.14 Writing Atom Feeds 407 13. Web Automation. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 413 13.1 Marking Up a Web Page 414 13.2 Cleaning Up Broken or Nonstandard HTML 416 13.3 Extracting Links from an HTML File 420 13.4 Converting Plain Text to HTML 422 13.5 Converting HTML to Plain Text 423 13.6 Removing HTML and PHP Tags 424 13.7 Responding to an Ajax Request 428 13.8 Integrating with JavaScript 429 13.9 Program: Finding Stale Links 433 13.10 Program: Finding Fresh Links 435 14. Consuming RESTful APIs. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 439 14.1 Fetching a URL with the GET Method 440 14.2 Fetching a URL with the POST Method and Form Data 444 viii | Table of Contents
  • 15. 14.3 Fetching a URL with an Arbitrary Method and POST Body 446 14.4 Fetching a URL with Cookies 448 14.5 Fetching a URL with Arbitrary Headers 450 14.6 Fetching a URL with a Timeout 451 14.7 Fetching an HTTPS URL 453 14.8 Debugging the Raw HTTP Exchange 453 14.9 Making an OAuth 1.0 Request 458 14.10 Making an OAuth 2.0 Request 460 15. Serving RESTful APIs. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 465 15.1 Exposing and Routing to a Resource 468 15.2 Exposing Clean Resource Paths 471 15.3 Exposing a Resource for Reading 472 15.4 Creating a Resource 474 15.5 Editing a Resource 479 15.6 Deleting a Resource 481 15.7 Indicating Errors and Failures 482 15.8 Supporting Multiple Formats 484 16. Internet Services. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 487 16.1 Sending Mail 488 16.2 Sending MIME Mail 490 16.3 Reading Mail with IMAP or POP3 491 16.4 Getting and Putting Files with FTP 495 16.5 Looking Up Addresses with LDAP 498 16.6 Using LDAP for User Authentication 499 16.7 Performing DNS Lookups 502 16.8 Checking If a Host Is Alive 504 16.9 Getting Information About a Domain Name 506 17. Graphics. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 509 17.1 Drawing Lines, Rectangles, and Polygons 512 17.2 Drawing Arcs, Ellipses, and Circles 515 17.3 Drawing with Patterned Lines 517 17.4 Drawing Text 518 17.5 Drawing Centered Text 520 17.6 Building Dynamic Images 524 17.7 Getting and Setting a Transparent Color 526 17.8 Overlaying Watermarks 527 17.9 Creating Thumbnail Images 530 17.10 Reading EXIF Data 533 17.11 Serving Images Securely 535 Table of Contents | ix
  • 16. 17.12 Program: Generating Bar Charts from Poll Results 536 18. Security and Encryption. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 541 18.1 Preventing Session Fixation 542 18.2 Protecting Against Form Spoofing 543 18.3 Ensuring Input Is Filtered 544 18.4 Avoiding Cross-Site Scripting 545 18.5 Eliminating SQL Injection 546 18.6 Keeping Passwords Out of Your Site Files 547 18.7 Storing Passwords 548 18.8 Dealing with Lost Passwords 551 18.9 Verifying Data with Hashes 553 18.10 Encrypting and Decrypting Data 555 18.11 Storing Encrypted Data in a File or Database 557 18.12 Sharing Encrypted Data with Another Website 560 18.13 Detecting SSL 562 18.14 Encrypting Email with GPG 563 19. Internationalization and Localization. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 567 19.1 Determining the User’s Locale 569 19.2 Localizing Text Messages 570 19.3 Localizing Dates and Times 573 19.4 Localizing Numbers 577 19.5 Localizing Currency Values 579 19.6 Localizing Images 581 19.7 Localizing Included Files 583 19.8 Sorting in a Locale-Aware Order 584 19.9 Managing Localization Resources 584 19.10 Setting the Character Encoding of Outgoing Data 587 19.11 Setting the Character Encoding of Incoming Data 587 19.12 Manipulating UTF-8 Text 588 20. Error Handling. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 593 20.1 Finding and Fixing Parse Errors 594 20.2 Creating Your Own Exception Classes 596 20.3 Printing a Stack Trace 599 20.4 Reading Configuration Variables 602 20.5 Setting Configuration Variables 603 20.6 Hiding Error Messages from Users 604 20.7 Tuning Error Handling 606 20.8 Using a Custom Error Handler 608 20.9 Logging Errors 609 x | Table of Contents
  • 17. 20.10 Eliminating “headers already sent” Errors 611 20.11 Logging Debugging Information 612 21. Software Engineering. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 615 21.1 Using a Debugger Extension 615 21.2 Writing a Unit Test 619 21.3 Writing a Unit Test Suite 620 21.4 Applying a Unit Test to a Web Page 622 21.5 Setting Up a Test Environment 624 21.6 Using the Built-in Web Server 625 22. Performance Tuning. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 629 22.1 Using an Accelerator 630 22.2 Timing Function Execution 631 22.3 Timing Program Execution by Function 632 22.4 Timing Program Execution by Statement 634 22.5 Timing Program Execution by Section 636 22.6 Profiling with a Debugger Extension 638 22.7 Stress-Testing Your Website 642 22.8 Avoiding Regular Expressions 643 23. Regular Expressions. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 647 23.1 Switching from ereg to preg 651 23.2 Matching Words 652 23.3 Finding the nth Occurrence of a Match 654 23.4 Choosing Greedy or Nongreedy Matches 656 23.5 Finding All Lines in a File That Match a Pattern 658 23.6 Capturing Text Inside HTML Tags 659 23.7 Preventing Parentheses from Capturing Text 660 23.8 Escaping Special Characters in a Regular Expression 662 23.9 Reading Records with a Pattern Separator 663 23.10 Using a PHP Function in a Regular Expression 664 24. Files. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 667 24.1 Creating or Opening a Local File 671 24.2 Creating a Temporary File 672 24.3 Opening a Remote File 673 24.4 Reading from Standard Input 674 24.5 Reading a File into a String 675 24.6 Counting Lines, Paragraphs, or Records in a File 676 24.7 Processing Every Word in a File 679 24.8 Picking a Random Line from a File 680 Table of Contents | xi
  • 18. 24.9 Randomizing All Lines in a File 681 24.10 Processing Variable-Length Text Fields 682 24.11 Reading Configuration Files 683 24.12 Modifying a File in Place Without a Temporary File 685 24.13 Flushing Output to a File 687 24.14 Writing to Standard Output 688 24.15 Writing to Many Filehandles Simultaneously 688 24.16 Escaping Shell Metacharacters 689 24.17 Passing Input to a Program 691 24.18 Reading Standard Output from a Program 692 24.19 Reading Standard Error from a Program 693 24.20 Locking a File 694 24.21 Reading and Writing Custom File Types 697 24.22 Reading and Writing Compressed Files 702 25. Directories. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 705 25.1 Getting and Setting File Timestamps 708 25.2 Getting File Information 709 25.3 Changing File Permissions or Ownership 710 25.4 Splitting a Filename into Its Component Parts 711 25.5 Deleting a File 713 25.6 Copying or Moving a File 713 25.7 Processing All Files in a Directory 714 25.8 Getting a List of Filenames Matching a Pattern 715 25.9 Processing All Files in a Directory Recursively 717 25.10 Making New Directories 717 25.11 Removing a Directory and Its Contents 718 25.12 Program: Web Server Directory Listing 719 25.13 Program: Site Search 723 26. Command-Line PHP. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 727 26.1 Parsing Program Arguments 729 26.2 Parsing Program Arguments with getopt 730 26.3 Reading from the Keyboard 732 26.4 Running PHP Code on Every Line of an Input File 734 26.5 Reading Passwords 736 26.6 Colorizing Console Output 738 26.7 Program: DOM Explorer 740 27. Packages. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 745 27.1 Defining and Installing Composer Dependencies 748 27.2 Finding Composer Packages 749 xii | Table of Contents
  • 19. 27.3 Installing Composer Packages 751 27.4 Using the PEAR Installer 754 27.5 Finding PEAR Packages 757 27.6 Finding Information About a Package 759 27.7 Installing PEAR Packages 760 27.8 Upgrading PEAR Packages 762 27.9 Uninstalling PEAR Packages 763 27.10 Installing PECL Packages 764 Index. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 767 Table of Contents | xiii
  • 21. Preface PHP is the engine behind millions of dynamic web applications. Its broad feature set, approachable syntax, and support for different operating systems and web servers have made it an ideal language for both rapid web development and the methodical con‐ struction of complex systems. One of the major reasons for PHP’s success as a web scripting language is its origins as atooltoprocessHTMLformsandcreatewebpages.ThismakesPHPveryweb-friendly. Additionally, it is eagerly promiscuous when it comes to external applications and li‐ braries. PHP can speak to a multitude of databases, and it knows numerous Internet protocols. PHP also makes it simple to parse form data and make HTTP requests. This web-specific focus carries over to the recipes and examples in the PHP Cookbook. This book is a collection of solutions to common tasks in PHP. We’ve tried to include material that will appeal to everyone from newbies to wizards. If we’ve succeeded, you’ll learn something (or perhaps many things) from PHP Cookbook. There are tips in here for everyday PHP programmers as well as for people coming to PHP with experience in another language. PHP, in source code and binary forms, is available for download free from http:// www.php.net/. The PHP website also contains installation instructions, comprehensive documentation, and pointers to online resources, user groups, mailing lists, and other PHP resources. Who This Book Is For This book is for programmers who need to solve problems with PHP. If you don’t know any PHP, make this your second PHP book. The first should be Learning PHP 5, also from O’Reilly. If you’re already familiar with PHP, this book helps you overcome a specific problem and get on with your life (or at least your programming activities). The PHP Cook‐ xv
  • 22. book can also show you how to accomplish a particular task in PHP, such as sending email or parsing JSON, that you may already know how to do in another language. Programmers converting applications from other languages to PHP will find this book a trusty companion. What Is in This Book We don’t expect that you’ll sit down and read this book from cover to cover (although we’ll be happy if you do!). PHP programmers are constantly faced with a wide variety of challenges on a wide range of subjects. Turn to the PHP Cookbook when you en‐ counter a problem you need to solve. Each recipe is a self-contained explanation that gives you a head start toward finishing your task. When a recipe refers to topics outside its scope, it contains pointers to related recipes and other online and offline resources. If you choose to read an entire chapter at once, that’s OK. The recipes generally flow from easy to hard, with example programs that “put it all together” at the end of many chapters. The chapter introduction provides an overview of the material covered in the chapter, including relevant background material, and points out a few highlighted rec‐ ipes of special interest. The book begins with four chapters about basic data types. Chapter 1 covers details like processing substrings, manipulating case, taking strings apart into smaller pieces, and parsing comma-separated data. Chapter 2 explains operations with floating-point num‐ bers, random numbers, converting between bases, and number formatting. Chapter 3 shows you how to manipulate dates and times, format them, handle time zones and daylight saving time, and find time to microsecond precision. Chapter 4 covers array operationslikeiterating,merging,reversing,sorting,andextractingparticularelements. Next are three chapters that discuss program building blocks. Chapter 5 covers notable features of PHP’s variable handling, such as default values, static variables, and pro‐ ducing string representations of complex data types. The recipes in Chapter 6 deal with using functions in PHP: processing arguments, passing and returning variables by ref‐ erence, creating functions at runtime, and scoping variables. Chapter 7 covers PHP’s object-oriented capabilities, with recipes on OOP basics as well as more advanced fea‐ tures, such as magic methods, destructors, access control, reflection, traits, and name‐ spaces. After the data types and building blocks come six chapters devoted to topics that are central to web programming. Chapter 8 covers cookies, headers, authentication, work‐ ing with query strings, and other fundamentals of web applications. Chapter 9 covers processing and validating form input, displaying multipage forms, showing forms with error messages, and guarding against problems such as cross-site scripting and multiple submissions of the same form. Chapter 10 explains the differences between DBM and SQL databases and, using the PDO database access abstraction layer, shows how to xvi | Preface
  • 23. connecttoadatabase,assignuniqueIDvalues,retrieverows,changedata,escapequotes, and log debugging information. Chapter 11 covers PHP’s built-in sessions module, which lets you maintain information about a user as he moves from page to page on your website. This chapter also highlights some of the security issues associated with sessions. Chapter 12 discusses all things XML: the SimpleXML extension and DOM functions, using XPath and XSLT, and reading and writing both RSS and Atom feeds. Chapter 13 explores topics useful to PHP applications that integrate with external web‐ sites and client-side JavaScript such as retrieving remote URLs, cleaning up HTML, and responding to an Ajax request. The next three chapters are all about network interaction. Chapter 14 details the ins and outs of consuming a web service—using an external REST service from within your code. Chapter 15 handles the other side of the web services equation—serving up REST requests to others. Both chapters discuss authentication, headers, and error handling. Chapter 16 discusses other network services such as sending email messages, using LDAP, and doing DNS lookups. The next section of the book is a series of chapters on features and extensions of PHP that help you build applications that are robust, secure, user-friendly, and efficient. Chapter 17 shows you how to create graphics, with recipes on drawing text, lines, polygons, and curves. Chapter 18 focuses on security topics such as avoiding session fixation and cross-site scripting, working with passwords, and encrypting data. Chap‐ ter 19 helps you make your applications globally friendly and includes recipes for lo‐ calizing text, dates and times, currency values, and images, as well as a recipe working with text in UTF-8 character encoding. Chapter 20 goes into detail on error handling and logging, while Chapter 21 discusses debugging techniques, writing tests for your code, and using PHP’s built-in web server. Chapter 22 explains how to compare the performance of two functions and provides tips on getting your programs to run at maximum speed. Chapter 23 covers regular expressions, including capturing text inside ofHTMLtags,callingaPHPfunctionfrominsidearegularexpression,andusinggreedy and nongreedy matching. Chapters24and25coverthefilesystem.Chapter24focusesonfiles:openingandclosing them, using temporary files, locking files, sending compressed files, and processing the contents of files. Chapter 25 deals with directories and file metadata, with recipes on changing file permissions and ownership, moving or deleting a file, and processing all files in a directory. Last, there are two chapters on topics that extend the reach of what PHP can do. Chap‐ ter 26 covers using PHP outside of web programming. Its recipes cover command-line topics such as parsing program arguments and reading passwords. Chapter 27 covers Composer, PEAR (PHP Extension and Application Repository), and PECL (PHP Ex‐ tension Community Library). Composer and PEAR provide access to a collection of PHP code that provides functions and extensions to PHP. PECL is a similar collection, Preface | xvii
  • 24. but of extensions to PHP written in C. We use PEAR and PECL modules throughout the book and Chapter 27 shows you how to install and upgrade them. Other Resources Websites There is a tremendous amount of PHP reference material online. With everything from the annotated PHP manual to sites with periodic articles and tutorials, a fast Internet connection rivals a large bookshelf in PHP documentary usefulness. Here are some key sites: The Annotated PHP Manual Availablein11languages,thissiteincludesbothofficialdocumentationoffunctions and language features as well as user-contributed comments. PHP mailing lists There are many PHP mailing lists covering installation, programming, extending PHP, and various other topics; there is also a read-only web interface to the mailing lists. PHP support resources This handy collection of support resources has information on PHP user groups, events, and other support channels. Composer Composer is a dependency manager for PHP that provides a structured way both to declare dependencies in your project and to install them. PEAR PEAR calls itself “a framework and distribution system for reusable PHP compo‐ nents.” You’ll find lots of useful PHP classes and sample code there. Read more about PEAR in Chapter 27. PECL PECL calls itself “a repository for PHP Extensions, providing a directory of exten‐ sions and hosting facilities for downloading and development of PHP extensions.” Read more about PECL in Chapter 27. PHP.net: A Tourist’s Guide This is a guide to the various websites under the php.net umbrella. PHP: The Right Way A quick reference that attempts to be a comprehensive source of PHP best practices. A great place to start if you’re wondering about the idiomatic way to do something in PHP. xviii | Preface
  • 25. Planet PHP An aggregation of blog posts by PHP developers, about PHP. SitePoint Blogs on PHP A good collection of information that explores PHP. Books Thissectionlistsbooksthatarehelpfulreferencesandtutorialsforbuildingapplications with PHP. Most are specific to web-related programming; look for books on MySQL, HTML, XML, and HTTP. At the end of the section, we’ve included a few books that are useful for every program‐ mer regardless of language of choice. These works can make you a better programmer by teaching you how to think about programming as part of a larger pattern of problem solving: • Learning PHP 5 by David Sklar (O’Reilly) • Programming PHP by Rasmus Lerdorf, Kevin Tatroe, and Peter MacIntyre (O’Reil‐ ly) • Extending and Embedding PHP by Sara Golemon (Sams) • Learning PHP, MySQL, JavaScript, and CSS by Robin Nixon (O’Reilly) • Mastering Regular Expressions by Jeffrey E. F. Friedl (O’Reilly) • MySQL Reference Manual • MySQL, by Paul DuBois (New Riders) • The Practice of Programming, by Brian W. Kernighan and Rob Pike (Addison- Wesley) • Programming Pearls by Jon Louis Bentley (Addison-Wesley) • The Mythical Man-Month, by Frederick P. Brooks (Addison-Wesley) Conventions Used in This Book Programming Conventions The examples in this book were written to run under PHP version 5.4.28 (and, where applicable, PHP 5.5.12). Sample code should work on both Unix and Windows, except where noted in the text. We’ve generally noted in the text when we depend on a feature added to PHP in or after 5.5. Preface | xix
  • 26. Some examples rely on the $php_errormsg variable, which is only available when the track_errors configuration directive is turned on. Typesetting Conventions The following typographic conventions are used in this book: Italic Used for commands, filenames, and example URLs. It is also used to define new terms when they first appear in the text. Constant width Used in code examples to show partial or complete PHP source code program listings. It is also used for class names, method names, variable names, and other fragments of PHP code. Constant width bold Used for user input, such as commands that you type on the command line. Constant width italic Shows text that should be replaced with user-supplied values or by values deter‐ mined by context. Comments and Questions Please address comments and questions concerning this book to the publisher: O’Reilly Media, Inc. 1005 Gravenstein Highway North Sebastopol, CA 95472 800-998-9938 (in the United States or Canada) 707-829-0515 (international or local) 707-829-0104 (fax) We have a web page for this book, where we list errata, examples, and any additional information. You can access this page at http://bit.ly/phpckbk3. To comment or ask technical questions about this book, send email to bookques tions@oreilly.com. For more information about our books, courses, conferences, and news, see our website at http://www.oreilly.com. Find us on Facebook: http://facebook.com/oreilly Follow us on Twitter: http://twitter.com/oreillymedia Watch us on YouTube: http://www.youtube.com/oreillymedia xx | Preface
  • 27. Acknowledgments Most importantly, a huge thanks to everyone who has contributed their time, creativity, and skills to making PHP what it is today. This amazing volunteer effort has created not only hundreds of thousands of lines of source code, but also comprehensive documen‐ tation, a QA infrastructure, lots of add-on applications and libraries, and a thriving user community worldwide. It’s a thrill and an honor to add the PHP Cookbook to the world of PHP. Thanks also to our reviewers: Paul Huff, Peter MacIntyre, Simon MacIntyre, and Russ Uman. Special mention to Chris Shiflett and Clay Lovelace for their contributions to the second edition of this book. And big thanks to the folks at O’Reilly that made this book a reality: Rachel Roumeliotis, Allyson MacDonald, Melanie Yarbrough, and Maria Gulick as well as the nameless orcs and dwarves that toil in the subterranean caverns of Sebastopol and Cambridge to make sure that the production process runs smoothly. David Sklar Thanks twice again to Adam. We’ve been working together (in one way or another) for 18 years and PHPing together for 17. There is still no one with whom I’d rather have written this book (except, to be completely honest, maybe Ben Franklin, if he could somehow be brought back to life). Thanks to my family members of all ages. You gave me the time and space to focus on the book. Now I will give you time and space to read the entire thing! Adam Trachtenberg David: It’s tough to complete with Ben Franklin. Please know that I support the turkey as the official animal of PHP instead of the elephant. Many thanks for your support over all these years, beginning long ago in the days of PHP/FI. Without you, this book would merely be a dream. Thanks to my family and friends for their support and encouragement over these many months. All my love to my two sons, even the one who helped me relearn that human children don’t give you extensions after 40 weeks if your work on PHP Cookbook isn’t complete. Finally, special thanks to my wife Elizabeth Anne; I should take your good advice more often. Preface | xxi
  • 29. CHAPTER 1 Strings 1.0 Introduction Strings in PHP are sequences of bytes, such as “We hold these truths to be self-evident” or “Once upon a time” or even “111211211.” When you read data from a file or output it to a web browser, your data is represented as strings. PHP strings are binary-safe (i.e., they can contain null bytes) and can grow and shrink on demand. Their size is limited only by the amount of memory that is available to PHP. Usually, PHP strings are ASCII strings. You must do extra work to handle non-ASCII data like UTF-8 or other multibyte character en‐ codings (see Chapter 19). Similar in form and behavior to Perl and the Unix shell, strings can be initialized in three ways: with single quotes, with double quotes, and with the “here document” (heredoc) format. With single-quoted strings, the only special characters you need to escape inside a string are the backslash and the single quote itself. This example shows four single-quoted strings: print 'I have gone to the store.'; print 'I've gone to the store.'; print 'Would you pay $1.75 for 8 ounces of tap water?'; print 'In double-quoted strings, newline is represented by n'; It prints: I have gone to the store. I've gone to the store. Would you pay $1.75 for 8 ounces of tap water? In double-quoted strings, newline is represented by n 1
  • 30. The preceding output shows what the raw output looks like. If you view it in a web browser, you will see all the sentences on the same line because HTML requires additional markup to insert line breaks. Because PHP doesn’t check for variable interpolation or almost any escape sequences in single-quoted strings, defining strings this way is straightforward and fast. Double-quoted strings don’t recognize escaped single quotes, but they do recognize interpolated variables and the escape sequences shown in Table 1-1. Table 1-1. Double-quoted string escape sequences Escape sequence Character n Newline (ASCII 10) r Carriage return (ASCII 13) t Tab (ASCII 9) Backslash $ Dollar sign " Double quote 0 through 777 Octal value x0 through xFF Hex value Example 1-1 shows some double-quoted strings. Example 1-1. Double-quoted strings print "I've gone to the store."; print "The sauce cost $10.25."; $cost = '$10.25'; print "The sauce cost $cost."; print "The sauce cost $061060.x32x35."; Example 1-1 prints: I've gone to the store. The sauce cost $10.25. The sauce cost $10.25. The sauce cost $10.25. The last line of Example 1-1 prints the price of sauce correctly because the character 1 is ASCII code 49 decimal and 061 octal. Character 0 is ASCII 48 decimal and 060 octal; 2 is ASCII 50 decimal and 32 hex; and 5 is ASCII 53 decimal and 35 hex. Heredoc-specified strings recognize all the interpolations and escapes of double-quoted strings, but they don’t require double quotes to be escaped. Heredocs start with <<< and 2 | Chapter 1: Strings
  • 31. a token. That token (with no leading or trailing whitespace), followed by a semicolon to end the statement (if necessary), ends the heredoc. Example 1-2 shows how to define a heredoc. Example 1-2. Defining a here document print <<< END It's funny when signs say things like: Original "Root" Beer "Free" Gift Shoes cleaned while "you" wait or have other misquoted words. END; Example 1-2 prints: It's funny when signs say things like: Original "Root" Beer "Free" Gift Shoes cleaned while "you" wait or have other misquoted words. Newlines, spacing, and quotes are all preserved in a heredoc. By convention, the end- of-string identifier is usually all caps, and it is case sensitive. Example 1-3 shows two more valid heredocs. Example 1-3. More here documents print <<< PARSLEY It's easy to grow fresh: Parsley Chives on your windowsill PARSLEY; print <<< DOGS If you like pets, yell out: DOGS AND CATS ARE GREAT! DOGS; Heredocs are especially useful for printing out HTML with interpolated variables be‐ cause you don’t have to escape the double quotes that appear in the HTML elements. Example 1-4 uses a heredoc to print HTML. Example 1-4. Printing HTML with a here document if ($remaining_cards > 0) { $url = '/deal.php'; $text = 'Deal More Cards'; } else { $url = '/new-game.php'; $text = 'Start a New Game'; } 1.0 Introduction | 3
  • 32. print <<< HTML There are <b>$remaining_cards</b> left. <p> <a href="$url">$text</a> HTML; In Example 1-4, the semicolon needs to go after the end-of-string delimiter to tell PHP the statement is ended. In some cases, however, you shouldn’t use the semicolon. One of these cases is shown in Example 1-5, which uses a heredoc with the string concate‐ nation operator. Example 1-5. Concatenation with a here document $html = <<< END <div class="$divClass"> <ul class="$ulClass"> <li> END . $listItem . '</li></div>'; print $html; Assuming some reasonable values for the $divClass, $ulClass, and $listItem vari‐ ables, Example 1-5 prints: <div class="class1">> <ul class="class2"> <li> The List Item </li></div> In Example 1-5, the expression needs to continue on the next line, so you don’t use a semicolon. Note also that in order for PHP to recognize the end-of-string delimiter, the . string concatenation operator needs to go on a separate line from the end-of-string delimiter. Nowdocs are similar to heredocs, but there is no variable interpolation. So, nowdocs are to heredocs as single-quoted strings are to double-quoted strings. They’re best when you have a block of non-PHP code, such as JavaScript, that you want to print as part of an HTML page or send to another program. For example, if you’re using jQuery: $js = <<<'__JS__' $.ajax({ 'url': '/api/getStock', 'data': { 'ticker': 'LNKD' }, 'success': function( data ) { $( "#stock-price" ).html( "<strong>$" + data + "</strong>" ); } }); 4 | Chapter 1: Strings
  • 33. __JS__; print $js; Individual bytes in strings can be referenced with square brackets. The first byte in the string is at index 0. Example 1-6 grabs one byte from a string. Example 1-6. Getting an individual byte in a string $neighbor = 'Hilda'; print $neighbor[3]; Example 1-6 prints: d 1.1 Accessing Substrings Problem You want to know if a string contains a particular substring. For example, you want to find out if an email address contains a @. Solution Use strpos(), as in Example 1-7. Example 1-7. Finding a substring with strpos( ) if (strpos($_POST['email'], '@') === false) { print 'There was no @ in the e-mail address!'; } Discussion The return value from strpos() is the first position in the string (the “haystack”) at which the substring (the “needle”) was found. If the needle wasn’t found at all in the haystack, strpos() returns false. If the needle is at the beginning of the haystack, strpos() returns 0 because position 0 represents the beginning of the string. To dif‐ ferentiate between return values of 0 and false, you must use the identity operator (===) or the not–identity operator (!==) instead of regular equals (==) or not-equals (!=). Example 1-7 compares the return value from strpos() to false using ===. This test only succeeds if strpos() returns false, not if it returns 0 or any other number. See Also Documentation on strpos(). 1.1 Accessing Substrings | 5
  • 34. 1.2 Extracting Substrings Problem You want to extract part of a string, starting at a particular place in the string. For example, you want the first eight characters of a username entered into a form. Solution Use substr() to select your substring, as in Example 1-8. Example 1-8. Extracting a substring with substr( ) $substring = substr($string,$start,$length); $username = substr($_GET['username'],0,8); Discussion If $start and $length are positive, substr() returns $length characters in the string, starting at $start. The first character in the string is at position 0. Example 1-9 has positive $start and $length. Example 1-9. Using substr( ) with positive $start and $length print substr('watch out for that tree',6,5); Example 1-9 prints: out f If you leave out $length, substr() returns the string from $start to the end of the original string, as shown in Example 1-10. Example 1-10. Using substr( ) with positive start and no length print substr('watch out for that tree',17); Example 1-10 prints: t tree If $start is bigger than the length of the string, substr() returns false. If $start plus $length goes past the end of the string, substr() returns all of the string from $start forward, as shown in Example 1-11. Example 1-11. Using substr( ) with length past the end of the string print substr('watch out for that tree',20,5); Example 1-11 prints: 6 | Chapter 1: Strings
  • 35. ree If $start is negative, substr() counts back from the end of the string to determine where your substring starts, as shown in Example 1-12. Example 1-12. Using substr( ) with negative start print substr('watch out for that tree',-6); print substr('watch out for that tree',-17,5); Example 1-12 prints: t tree out f With a negative $start value that goes past the beginning of the string (for example, if $start is −27 with a 20-character string), substr() behaves as if $start is 0. If $length is negative, substr() counts back from the end of the string to determine where your substring ends, as shown in Example 1-13. Example 1-13. Using substr( ) with negative length print substr('watch out for that tree',15,-2); print substr('watch out for that tree',-4,-1); Example 1-13 prints: hat tr tre See Also Documentation on substr(). 1.3 Replacing Substrings Problem You want to replace a substring with a different string. For example, you want to obscure all but the last four digits of a credit card number before printing it. Solution Use substr_replace(), as in Example 1-14. Example 1-14. Replacing a substring with substr_replace( ) // Everything from position $start to the end of $old_string // becomes $new_substring $new_string = substr_replace($old_string,$new_substring,$start); 1.3 Replacing Substrings | 7
  • 36. // $length characters, starting at position $start, become $new_substring $new_string = substr_replace($old_string,$new_substring,$start,$length); Discussion Without the $length argument, substr_replace() replaces everything from $start to the end of the string. If $length is specified, only that many characters are replaced: print substr_replace('My pet is a blue dog.','fish.',12); print substr_replace('My pet is a blue dog.','green',12,4); $credit_card = '4111 1111 1111 1111'; print substr_replace($credit_card,'xxxx ',0,strlen($credit_card)-4); My pet is a fish. My pet is a green dog. xxxx 1111 If $start is negative, the new substring is placed by counting $start characters from the end of $old_string, not from the beginning: print substr_replace('My pet is a blue dog.','fish.',-9); print substr_replace('My pet is a blue dog.','green',-9,4); My pet is a fish. My pet is a green dog. If $start and $length are 0, the new substring is inserted at the start of $old_string: print substr_replace('My pet is a blue dog.','Title: ',0,0); Title: My pet is a blue dog. The function substr_replace() is useful when you’ve got text that’s too big to display all at once, and you want to display some of the text with a link to the rest. Example 1-15 displays the first 25 characters of a message with an ellipsis after it as a link to a page that displays more text. Example 1-15. Displaying long text with an ellipsis $r = mysql_query("SELECT id,message FROM messages WHERE id = $id") or die(); $ob = mysql_fetch_object($r); printf('<a href="more-text.php?id=%d">%s</a>', $ob->id, substr_replace($ob->message,' ...',25)); The more-text.php page referenced in Example 1-15 can use the message ID passed in the query string to retrieve the full message and display it. See Also Documentation on substr_replace(). 8 | Chapter 1: Strings
  • 37. 1.4 Processing a String One Byte at a Time Problem You need to process each byte in a string individually. Solution Loop through each byte in the string with for. Example 1-16 counts the vowels in a string. Example 1-16. Processing each byte in a string $string = "This weekend, I'm going shopping for a pet chicken."; $vowels = 0; for ($i = 0, $j = strlen($string); $i < $j; $i++) { if (strstr('aeiouAEIOU',$string[$i])) { $vowels++; } } Discussion Processing a string a character at a time is an easy way to calculate the “Look and Say” sequence, as shown in Example 1-17. Example 1-17. The Look and Say sequence function lookandsay($s) { // initialize the return value to the empty string $r = ''; // $m holds the character we're counting, initialize to the first // character in the string $m = $s[0]; // $n is the number of $m's we've seen, initialize to 1 $n = 1; for ($i = 1, $j = strlen($s); $i < $j; $i++) { // if this character is the same as the last one if ($s[$i] == $m) { // increment the count of this character $n++; } else { // otherwise, add the count and character to the return value $r .= $n.$m; // set the character we're looking for to the current one $m = $s[$i]; // and reset the count to 1 $n = 1; } } // return the built up string as well as the last count and character 1.4 Processing a String One Byte at a Time | 9
  • 38. return $r.$n.$m; } for ($i = 0, $s = 1; $i < 10; $i++) { $s = lookandsay($s); print "$sn"; } Example 1-17 prints: 1 11 21 1211 111221 312211 13112221 1113213211 31131211131221 13211311123113112211 It’s called the “Look and Say” sequence because each element is what you get by looking at the previous element and saying what’s in it. For example, looking at the first element, 1, you say “one one.” So the second element is “11.” That’s two ones, so the third element is “21.” Similarly, that’s one two and one one, so the fourth element is “1211,” and so on. See Also Documentation on for; more about the “Look and Say” sequence. 1.5 Reversing a String by Word or Byte Problem You want to reverse the words or the bytes in a string. Solution Use strrev() to reverse by byte, as in Example 1-18. Example 1-18. Reversing a string by byte print strrev('This is not a palindrome.'); Example 1-18 prints: .emordnilap a ton si sihT To reverse by words, explode the string by word boundary, reverse the words, and then rejoin, as in Example 1-19. 10 | Chapter 1: Strings
  • 39. Example 1-19. Reversing a string by word $s = "Once upon a time there was a turtle."; // break the string up into words $words = explode(' ',$s); // reverse the array of words $words = array_reverse($words); // rebuild the string $s = implode(' ',$words); print $s; Example 1-19 prints: turtle. a was there time a upon Once Discussion Reversing a string by words can also be done all in one line with the code in Example 1-20. Example 1-20. Concisely reversing a string by word $reversed_s = implode(' ',array_reverse(explode(' ',$s))); See Also Recipe 24.7 discusses the implications of using something other than a space character as your word boundary; documentation on strrev() and array_reverse(). 1.6 Generating a Random String Problem You want to generate a random string. Solution Use str_rand(): function str_rand($length = 32, $characters = ↵ '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ') { if (!is_int($length) || $length < 0) { return false; } $characters_length = strlen($characters) - 1; $string = ''; 1.6 Generating a Random String | 11
  • 40. for ($i = $length; $i > 0; $i--) { $string .= $characters[mt_rand(0, $characters_length)]; } return $string; } Discussion PHP has native functions for generating random numbers, but nothing for random strings. The str_rand() function returns a 32-character string constructed from letters and numbers. Pass in an integer to change the length of the returned string. To use an alternative set of characters, pass them as a string as the second argument. For example, to get a 16- digit Morse Code: print str_rand(16, '.-'); .--..-.-.--.---- See Also Recipe 2.5 for generating random numbers. 1.7 Expanding and Compressing Tabs Problem You want to change spaces to tabs (or tabs to spaces) in a string while keeping text aligned with tab stops. For example, you want to display formatted text to users in a standardized way. Solution Use str_replace() to switch spaces to tabs or tabs to spaces, as shown in Example 1-21. Example 1-21. Switching tabs and spaces $rows = $db->query('SELECT message FROM messages WHERE id = 1'); $obj = $rows->fetch(PDO::FETCH_OBJ); $tabbed = str_replace(' ' , "t", $obj->message); $spaced = str_replace("t", ' ' , $obj->message); print "With Tabs: <pre>$tabbed</pre>"; print "With Spaces: <pre>$spaced</pre>"; 12 | Chapter 1: Strings
  • 41. Using str_replace() for conversion, however, doesn’t respect tab stops. If you want tab stops every eight characters, a line beginning with a five-letter word and a tab should have that tab replaced with three spaces, not one. Use the tab_expand() function shown in Example 1-22 to turn tabs to spaces in a way that respects tab stops. Example 1-22. tab_expand( ) function tab_expand($text) { while (strstr($text,"t")) { $text = preg_replace_callback('/^([^tn]*)(t+)/m', 'tab_expand_helper', $text); } return $text; } function tab_expand_helper($matches) { $tab_stop = 8; return $matches[1] . str_repeat(' ',strlen($matches[2]) * $tab_stop - (strlen($matches[1]) % $tab_stop)); } $spaced = tab_expand($obj->message); You can use the tab_unexpand() function shown in Example 1-23 to turn spaces back to tabs. Example 1-23. tab_unexpand( ) function tab_unexpand($text) { $tab_stop = 8; $lines = explode("n",$text); foreach ($lines as $i => $line) { // Expand any tabs to spaces $line = tab_expand($line); $chunks = str_split($line, $tab_stop); $chunkCount = count($chunks); // Scan all but the last chunk for ($j = 0; $j < $chunkCount - 1; $j++) { $chunks[$j] = preg_replace('/ {2,}$/',"t",$chunks[$j]); } // If the last chunk is a tab-stop's worth of spaces // convert it to a tab; Otherwise, leave it alone if ($chunks[$chunkCount-1] == str_repeat(' ', $tab_stop)) { $chunks[$chunkCount-1] = "t"; } // Recombine the chunks $lines[$i] = implode('',$chunks); } // Recombine the lines 1.7 Expanding and Compressing Tabs | 13
  • 42. return implode("n",$lines); } $tabbed = tab_unexpand($obj->message); Both functions take a string as an argument and return the string appropriately modi‐ fied. Discussion Each function assumes tab stops are every eight spaces, but that can be modified by changing the setting of the $tab_stop variable. The regular expression in tab_expand() matches both a group of tabs and all the text in a line before that group of tabs. It needs to match the text before the tabs because the length of that text affects how many spaces the tabs should be replaced with so that subsequent text is aligned with the next tab stop. The function doesn’t just replace each tab with eight spaces; it adjusts text after tabs to line up with tab stops. Similarly, tab_unexpand() doesn’t just look for eight consecutive spaces and then re‐ place them with one tab character. It divides up each line into eight-character chunks and then substitutes ending whitespace in those chunks (at least two spaces) with tabs. This not only preserves text alignment with tab stops; it also saves space in the string. See Also Documentation on str_replace(), on preg_replace_callback(), and on str_split(). Recipe 23.10 has more information on preg_replace_callback(). 1.8 Controlling Case Problem You need to capitalize, lowercase, or otherwise modify the case of letters in a string. For example, you want to capitalize the initial letters of names but lowercase the rest. Solution Use ucfirst() or ucwords() to capitalize the first letter of one or more words, as shown in Example 1-24. Example 1-24. Capitalizing letters print ucfirst("how do you do today?"); print ucwords("the prince of wales"); 14 | Chapter 1: Strings
  • 43. Example 1-24 prints: How do you do today? The Prince Of Wales Use strtolower() or strtoupper() to modify the case of entire strings, as in Example 1-25. Example 1-25. Changing case of strings print strtoupper("i'm not yelling!"); print strtolower('<A HREF="one.php">one</A>'); Example 1-25 prints: I'M NOT YELLING! <a href="one.php">one</a> Discussion Use ucfirst() to capitalize the first character in a string: print ucfirst('monkey face'); print ucfirst('1 monkey face'); This prints: Monkey face 1 monkey face Note that the second phrase is not “1 Monkey face.” Use ucwords() to capitalize the first character of each word in a string: print ucwords('1 monkey face'); print ucwords("don't play zone defense against the philadelphia 76-ers"); This prints: 1 Monkey Face Don't Play Zone Defense Against The Philadelphia 76-ers As expected, ucwords() doesn’t capitalize the “t” in “don’t.” But it also doesn’t capitalize the “e” in “76-ers.” For ucwords(), a word is any sequence of nonwhitespace characters that follows one or more whitespace characters. Because both ' and - aren’t whitespace characters,ucwords() doesn’tconsiderthe“t”in“don’t”orthe“e”in“76-ers”tobeword- starting characters. Both ucfirst() and ucwords() don’t change the case of non–first letters: print ucfirst('macWorld says I should get an iBook'); print ucwords('eTunaFish.com might buy itunaFish.Com!'); This prints: 1.8 Controlling Case | 15
  • 44. MacWorld says I should get an iBook ETunaFish.com Might Buy ItunaFish.Com! The functions strtolower() and strtoupper() work on entire strings, not just indi‐ vidual characters. All alphabetic characters are changed to lowercase by strtolow er() and strtoupper() changes all alphabetic characters to uppercase: print strtolower("I programmed the WOPR and the TRS-80."); print strtoupper('"since feeling is first" is a poem by e. e. cummings.'); This prints: i programmed the wopr and the trs-80. "SINCE FEELING IS FIRST" IS A POEM BY E. E. CUMMINGS. When determining upper- and lowercase, these functions respect your locale settings. See Also For more information about locale settings, see Chapter 19; documentation on uc first(), ucwords(), strtolower(), and strtoupper(). 1.9 Interpolating Functions and Expressions Within Strings Problem You want to include the results of executing a function or expression within a string. Solution Use the string concatenation operator (.), as shown in Example 1-26, when the value you want to include can’t be inside the string. Example 1-26. String concatenation print 'You have '.($_POST['boys'] + $_POST['girls']).' children.'; print "The word '$word' is ".strlen($word).' characters long.'; print 'You owe '.$amounts['payment'].' immediately.'; print "My circle's diameter is ".$circle->getDiameter().' inches.'; Discussion You can put variables, object properties, and array elements (if the subscript is unquo‐ ted) directly in double-quoted strings: print "I have $children children."; print "You owe $amounts[payment] immediately."; print "My circle's diameter is $circle->diameter inches."; 16 | Chapter 1: Strings
  • 45. Interpolation with double-quoted strings places some limitations on the syntax of what can be interpolated. In the previous example, $amounts['payment'] had to be written as $amounts[payment] so it would be interpolated properly. Use curly braces around more complicated expressions to interpolate them into a string. For example: print "I have {$children} children."; print "You owe {$amounts['payment']} immediately."; print "My circle's diameter is {$circle->getDiameter()} inches."; Direct interpolation or using string concatenation also works with heredocs. Interpo‐ lating with string concatenation in heredocs can look a little strange because the closing heredoc delimiter and the string concatenation operator have to be on separate lines: print <<< END Right now, the time is END . strftime('%c') . <<< END but tomorrow it will be END . strftime('%c',time() + 86400); Also, if you’re interpolating with heredocs, make sure to include appropriate spacing for the whole string to appear properly. In the previous example, Right now, the time is has to include a trailing space, and but tomorrow it will be has to include leading and trailing spaces. See Also For the syntax to interpolate variable variables (such as ${"amount_$i"}), see Recipe 5.4; documentation on the string concatenation operator. 1.10 Trimming Blanks from a String Problem You want to remove whitespace from the beginning or end of a string. For example, you want to clean up user input before validating it. Solution Use ltrim(), rtrim(), or trim(). The ltrim() function removes whitespace from the beginning of a string, rtrim() from the end of a string, and trim() from both the beginning and end of a string: $zipcode = trim($_GET['zipcode']); $no_linefeed = rtrim($_GET['text']); $name = ltrim($_GET['name']); 1.10 Trimming Blanks from a String | 17
  • 46. Discussion For these functions, whitespace is defined as the following characters: newline, carriage return, space, horizontal and vertical tab, and null. Trimming whitespace off of strings saves storage space and can make for more precise display of formatted data or text within <pre> tags, for example. If you are doing com‐ parisonswithuserinput,youshouldtrimthedatafirst,sothatsomeonewhomistakenly enters 98052 followed by a few spaces as their zip code isn’t forced to fix an error that really isn’t one. Trimming before exact text comparisons also ensures that, for example, “salamin” equals “salami.” It’s also a good idea to normalize string data by trimming it before storing it in a database. The trim() functions can also remove user-specified characters from strings. Pass the characters you want to remove as a second argument. You can indicate a range of char‐ acters with two dots between the first and last characters in the range: // Remove numerals and space from the beginning of the line print ltrim('10 PRINT A$',' 0..9'); // Remove semicolon from the end of the line print rtrim('SELECT * FROM turtles;',';'); This prints: PRINT A$ SELECT * FROM turtles PHP also provides chop() as an alias for rtrim(). However, you’re best off using rtrim() instead because PHP’s chop() behaves differently than Perl’s chop() (which is deprecated in favor of chomp(), anyway), and using it can confuse others when they read your code. See Also Documentation on trim(), ltrim(), and rtrim(). 1.11 Generating Comma-Separated Data Problem You want to format data as comma-separated values (CSV) so that it can be imported by a spreadsheet or database. Solution Use the fputcsv() function to generate a CSV-formatted line from an array of data. Example 1-27 writes the data in $sales into a file. 18 | Chapter 1: Strings
  • 47. Example 1-27. Generating comma-separated data $sales = array( array('Northeast','2005-01-01','2005-02-01',12.54), array('Northwest','2005-01-01','2005-02-01',546.33), array('Southeast','2005-01-01','2005-02-01',93.26), array('Southwest','2005-01-01','2005-02-01',945.21), array('All Regions','--','--',1597.34) ); $filename = './sales.csv'; $fh = fopen($filename,'w') or die("Can't open $filename"); foreach ($sales as $sales_line) { if (fputcsv($fh, $sales_line) === false) { die("Can't write CSV line"); } } fclose($fh) or die("Can't close $filename"); Discussion To print the CSV-formatted data instead of writing it to a file, use the special output stream php://output, as shown in Example 1-28. Example 1-28. Printing comma-separated data $sales = array( array('Northeast','2005-01-01','2005-02-01',12.54), array('Northwest','2005-01-01','2005-02-01',546.33), array('Southeast','2005-01-01','2005-02-01',93.26), array('Southwest','2005-01-01','2005-02-01',945.21), array('All Regions','--','--',1597.34) ); $fh = fopen('php://output','w'); foreach ($sales as $sales_line) { if (fputcsv($fh, $sales_line) === false) { die("Can't write CSV line"); } } fclose($fh); To put the CSV-formatted data into a string instead of printing it or writing it to a file, combine the technique in Example 1-28 with output buffering, as shown in Example 1-29. Example 1-29. Putting comma-separated data into a string $sales = array( array('Northeast','2005-01-01','2005-02-01',12.54), array('Northwest','2005-01-01','2005-02-01',546.33), array('Southeast','2005-01-01','2005-02-01',93.26), array('Southwest','2005-01-01','2005-02-01',945.21), array('All Regions','--','--',1597.34) ); ob_start(); 1.11 Generating Comma-Separated Data | 19
  • 48. $fh = fopen('php://output','w') or die("Can't open php://output"); foreach ($sales as $sales_line) { if (fputcsv($fh, $sales_line) === false) { die("Can't write CSV line"); } } fclose($fh) or die("Can't close php://output"); $output = ob_get_contents(); ob_end_clean(); See Also Documentation on fputcsv(); Recipe 8.13 has more information about output buffer‐ ing. 1.12 Parsing Comma-Separated Data Problem You have data in comma-separated values (CSV) format—for example, a file exported from Excel or a database—and you want to extract the records and fields into a format you can manipulate in PHP. Solution If the CSV data is in a file (or available via a URL), open the file with fopen() and read in the data with fgetcsv(). Example 1-30 prints out CSV data in an HTML table. Example 1-30. Reading CSV data from a file $fp = fopen($filename,'r') or die("can't open file"); print "<table>n"; while($csv_line = fgetcsv($fp)) { print '<tr>'; for ($i = 0, $j = count($csv_line); $i < $j; $i++) { print '<td>'.htmlentities($csv_line[$i]).'</td>'; } print "</tr>n"; } print "</table>n"; fclose($fp) or die("can't close file"); Discussion By default, fgetcsv() reads in an entire line of data. If your average line length is more than 8,192 bytes, your program may run faster if you specify an explicit line length instead of letting PHP figure it out. Do this by providing a second argument to fgetcsv() that is a value larger than the maximum length of a line in your CSV file. 20 | Chapter 1: Strings
  • 49. (Don’t forget to count the end-of-line whitespace.) If you pass a line length of 0, PHP will use the default behavior. You can pass fgetcsv() an optional third argument, a delimiter to use instead of a comma (,). However, using a different delimiter somewhat defeats the purpose of CSV as an easy way to exchange tabular data. Don’t be tempted to bypass fgetcsv() and just read a line in and explode() on the commas. CSV is more complicated than that so that it can deal with field values that have, for example, literal commas in them that should not be treated as field delimiters. Using fgetcsv() protects you and your code from subtle errors. See Also Documentation on fgetcsv(). 1.13 Generating Fixed-Width Field Data Records Problem You need to format data records such that each field takes up a set amount of characters. Solution Use pack() with a format string that specifies a sequence of space-padded strings. Example 1-31 transforms an array of data into fixed-width records. Example 1-31. Generating fixed-width field data records $books = array( array('Elmer Gantry', 'Sinclair Lewis', 1927), array('The Scarlatti Inheritance','Robert Ludlum', 1971), array('The Parsifal Mosaic','William Styron', 1979) ); foreach ($books as $book) { print pack('A25A15A4', $book[0], $book[1], $book[2]) . "n"; } Discussion The format string A25A14A4 tells pack() to transform its subsequent arguments into a 25-character space-padded string, a 14-character space-padded string, and a 4- character space-padded string. For space-padded fields in fixed-width records, pack() provides a concise solution. To pad fields with something other than a space, however, use substr() to ensure that the field values aren’t too long and str_pad() to ensure that the field values aren’t too 1.13 Generating Fixed-Width Field Data Records | 21
  • 50. short. Example 1-32 transforms an array of records into fixed-width records with .-padded fields. Example 1-32. Generating fixed-width field data records without pack( ) $books = array( array('Elmer Gantry', 'Sinclair Lewis', 1927), array('The Scarlatti Inheritance','Robert Ludlum', 1971), array('The Parsifal Mosaic','William Styron', 1979) ); foreach ($books as $book) { $title = str_pad(substr($book[0], 0, 25), 25, '.'); $author = str_pad(substr($book[1], 0, 15), 15, '.'); $year = str_pad(substr($book[2], 0, 4), 4, '.'); print "$title$author$yearn"; } See Also Documentation on pack() and on str_pad(). Recipe 1.17 discusses pack() format strings in more detail. 1.14 Parsing Fixed-Width Field Data Records Problem You need to break apart fixed-width records in strings. Solution Use substr() as shown in Example 1-33. Example 1-33. Parsing fixed-width records with substr( ) $fp = fopen('fixed-width-records.txt','r',true) or die ("can't open file"); while ($s = fgets($fp,1024)) { $fields[1] = substr($s,0,25); // first field: first 25 characters of the line $fields[2] = substr($s,25,15); // second field: next 15 characters of the line $fields[3] = substr($s,40,4); // third field: next 4 characters of the line $fields = array_map('rtrim', $fields); // strip the trailing whitespace // a function to do something with the fields process_fields($fields); } fclose($fp) or die("can't close file"); Or unpack(), as shown in Example 1-34. Example 1-34. Parsing fixed-width records with unpack( ) function fixed_width_unpack($format_string,$data) { $r = array(); 22 | Chapter 1: Strings
  • 51. for ($i = 0, $j = count($data); $i < $j; $i++) { $r[$i] = unpack($format_string,$data[$i]); } return $r; } Discussion Data in which each field is allotted a fixed number of characters per line may look like this list of books, titles, and publication dates: $booklist=<<<END Elmer Gantry Sinclair Lewis 1927 The Scarlatti InheritanceRobert Ludlum 1971 The Parsifal Mosaic Robert Ludlum 1982 Sophie's Choice William Styron 1979 END; In each line, the title occupies the first 25 characters, the author’s name the next 15 characters, and the publication year the next 4 characters. Knowing those field widths, you can easily use substr() to parse the fields into an array: $books = explode("n",$booklist); for($i = 0, $j = count($books); $i < $j; $i++) { $book_array[$i]['title'] = substr($books[$i],0,25); $book_array[$i]['author'] = substr($books[$i],25,15); $book_array[$i]['publication_year'] = substr($books[$i],40,4); } Exploding $booklist into an array of lines makes the looping code the same whether it’s operating over a string or a series of lines read in from a file. The loop can be made more flexible by specifying the field names and widths in a separate array that can be passed to a parsing function, as shown in the fixed_width_substr() function in Example 1-35. Example 1-35. fixed_width_substr( ) function fixed_width_substr($fields,$data) { $r = array(); for ($i = 0, $j = count($data); $i < $j; $i++) { $line_pos = 0; foreach($fields as $field_name => $field_length) { $r[$i][$field_name] = rtrim(substr($data[$i],$line_pos,$field_length)); $line_pos += $field_length; } } return $r; } $book_fields = array('title' => 25, 1.14 Parsing Fixed-Width Field Data Records | 23
  • 52. 'author' => 15, 'publication_year' => 4); $book_array = fixed_width_substr($book_fields,$booklist); The variable $line_pos keeps track of the start of each field and is advanced by the previous field’s width as the code moves through each line. Use rtrim() to remove trailing whitespace from each field. You can use unpack() as a substitute for substr() to extract fields. Instead of specifying the field names and widths as an associative array, create a format string for unpack(). A fixed-width field extractor using unpack() looks like the fixed_width_unpack() function shown in Example 1-36. Example 1-36. fixed_width_unpack( ) function fixed_width_unpack($format_string,$data) { $r = array(); for ($i = 0, $j = count($data); $i < $j; $i++) { $r[$i] = unpack($format_string,$data[$i]); } return $r; } BecausetheA formattounpack() meansspace-padded string,there’snoneedtortrim() off the trailing spaces. Once the fields have been parsed into $book_array by either function, the data can be printed as an HTML table, for example: $book_array = fixed_width_unpack('A25title/A15author/A4publication_year', $books); print "<table>n"; // print a header row print '<tr><td>'; print join('</td><td>',array_keys($book_array[0])); print "</td></tr>n"; // print each data row foreach ($book_array as $row) { print '<tr><td>'; print join('</td><td>',array_values($row)); print "</td></tr>n"; } print "</table>n"; Joining data on </td><td> produces a table row that is missing its first <td> and last </td>. We produce a complete table row by printing out <tr><td> before the joined data and </td></tr> after the joined data. 24 | Chapter 1: Strings
  • 53. Both substr() and unpack() have equivalent capabilities when the fixed-width fields are strings, but unpack() is the better solution when the elements of the fields aren’t just strings. If all of your fields are the same size, str_split() is a handy shortcut for chopping up incoming data. It returns an array made up of sections of a string. Example 1-37 uses str_split() to break apart a string into 32-byte pieces. Example 1-37. Chopping up a string with str_split( ) $fields = str_split($line_of_data,32); // $fields[0] is bytes 0 - 31 // $fields[1] is bytes 32 - 63 // and so on See Also For more information about unpack(), see Recipe 1.17 and the PHP website; docu‐ mentation on str_split(); Recipe 4.8 discusses join(). 1.15 Taking Strings Apart Problem You need to break a string into pieces. For example, you want to access each line that a user enters in a <textarea> form field. Solution Use explode() if what separates the pieces is a constant string: $words = explode(' ','My sentence is not very complicated'); Use preg_split() if you need a Perl-compatible regular expression to describe the separator: $words = preg_split('/d. /','my day: 1. get up 2. get dressed 3. eat toast'); $lines = preg_split('/[nr]+/',$_POST['textarea']); Use the /i flag to preg_split() for case-insensitive separator matching: $words = preg_split('/ x /i','31 inches x 22 inches X 9 inches'); Discussion The simplest solution of the bunch is explode(). Pass it your separator string, the string to be separated, and an optional limit on how many elements should be returned: 1.15 Taking Strings Apart | 25
  • 54. $dwarves = 'dopey,sleepy,happy,grumpy,sneezy,bashful,doc'; $dwarf_array = explode(',',$dwarves); This makes $dwarf_array a seven-element array, so print_r($dwarf_array) prints: Array ( [0] => dopey [1] => sleepy [2] => happy [3] => grumpy [4] => sneezy [5] => bashful [6] => doc ) If the specified limit is less than the number of possible chunks, the last chunk contains the remainder: $dwarf_array = explode(',',$dwarves,5); print_r($dwarf_array); This prints: Array ( [0] => dopey [1] => sleepy [2] => happy [3] => grumpy [4] => sneezy,bashful,doc ) The separator is treated literally by explode(). If you specify a comma and a space as a separator, it breaks the string only on a comma followed by a space, not on a comma or a space. With preg_split(), you have more flexibility. Instead of a string literal as a separator, it uses a Perl-compatible regular expression engine. With preg_split(), you can take advantage of various Perl-ish regular expression extensions, as well as tricks such as including the separator text in the returned array of strings: $math = "3 + 2 / 7 - 9"; $stack = preg_split('/ *([+-/*]) */',$math,-1,PREG_SPLIT_DELIM_CAPTURE); print_r($stack); This prints: Array ( [0] => 3 [1] => + [2] => 2 [3] => / 26 | Chapter 1: Strings
  • 55. Another Random Document on Scribd Without Any Related Topics
  • 56. This eBook is for the use of anyone anywhere in the United States and most other parts of the world at no cost and with almost no restrictions whatsoever. You may copy it, give it away or re-use it under the terms of the Project Gutenberg License included with this eBook or online at www.gutenberg.org. If you are not located in the United States, you will have to check the laws of the country where you are located before using this eBook. 1.E.2. If an individual Project Gutenberg™ electronic work is derived from texts not protected by U.S. copyright law (does not contain a notice indicating that it is posted with permission of the copyright holder), the work can be copied and distributed to anyone in the United States without paying any fees or charges. If you are redistributing or providing access to a work with the phrase “Project Gutenberg” associated with or appearing on the work, you must comply either with the requirements of paragraphs 1.E.1 through 1.E.7 or obtain permission for the use of the work and the Project Gutenberg™ trademark as set forth in paragraphs 1.E.8 or 1.E.9. 1.E.3. If an individual Project Gutenberg™ electronic work is posted with the permission of the copyright holder, your use and distribution must comply with both paragraphs 1.E.1 through 1.E.7 and any additional terms imposed by the copyright holder. Additional terms will be linked to the Project Gutenberg™ License for all works posted with the permission of the copyright holder found at the beginning of this work. 1.E.4. Do not unlink or detach or remove the full Project Gutenberg™ License terms from this work, or any files containing a part of this work or any other work associated with Project Gutenberg™. 1.E.5. Do not copy, display, perform, distribute or redistribute this electronic work, or any part of this electronic work, without prominently displaying the sentence set forth in paragraph 1.E.1
  • 57. with active links or immediate access to the full terms of the Project Gutenberg™ License. 1.E.6. You may convert to and distribute this work in any binary, compressed, marked up, nonproprietary or proprietary form, including any word processing or hypertext form. However, if you provide access to or distribute copies of a Project Gutenberg™ work in a format other than “Plain Vanilla ASCII” or other format used in the official version posted on the official Project Gutenberg™ website (www.gutenberg.org), you must, at no additional cost, fee or expense to the user, provide a copy, a means of exporting a copy, or a means of obtaining a copy upon request, of the work in its original “Plain Vanilla ASCII” or other form. Any alternate format must include the full Project Gutenberg™ License as specified in paragraph 1.E.1. 1.E.7. Do not charge a fee for access to, viewing, displaying, performing, copying or distributing any Project Gutenberg™ works unless you comply with paragraph 1.E.8 or 1.E.9. 1.E.8. You may charge a reasonable fee for copies of or providing access to or distributing Project Gutenberg™ electronic works provided that: • You pay a royalty fee of 20% of the gross profits you derive from the use of Project Gutenberg™ works calculated using the method you already use to calculate your applicable taxes. The fee is owed to the owner of the Project Gutenberg™ trademark, but he has agreed to donate royalties under this paragraph to the Project Gutenberg Literary Archive Foundation. Royalty payments must be paid within 60 days following each date on which you prepare (or are legally required to prepare) your periodic tax returns. Royalty payments should be clearly marked as such and sent to the Project Gutenberg Literary Archive Foundation at the address specified in Section 4, “Information
  • 58. about donations to the Project Gutenberg Literary Archive Foundation.” • You provide a full refund of any money paid by a user who notifies you in writing (or by e-mail) within 30 days of receipt that s/he does not agree to the terms of the full Project Gutenberg™ License. You must require such a user to return or destroy all copies of the works possessed in a physical medium and discontinue all use of and all access to other copies of Project Gutenberg™ works. • You provide, in accordance with paragraph 1.F.3, a full refund of any money paid for a work or a replacement copy, if a defect in the electronic work is discovered and reported to you within 90 days of receipt of the work. • You comply with all other terms of this agreement for free distribution of Project Gutenberg™ works. 1.E.9. If you wish to charge a fee or distribute a Project Gutenberg™ electronic work or group of works on different terms than are set forth in this agreement, you must obtain permission in writing from the Project Gutenberg Literary Archive Foundation, the manager of the Project Gutenberg™ trademark. Contact the Foundation as set forth in Section 3 below. 1.F. 1.F.1. Project Gutenberg volunteers and employees expend considerable effort to identify, do copyright research on, transcribe and proofread works not protected by U.S. copyright law in creating the Project Gutenberg™ collection. Despite these efforts, Project Gutenberg™ electronic works, and the medium on which they may be stored, may contain “Defects,” such as, but not limited to, incomplete, inaccurate or corrupt data, transcription errors, a copyright or other intellectual property infringement, a defective or
  • 59. damaged disk or other medium, a computer virus, or computer codes that damage or cannot be read by your equipment. 1.F.2. LIMITED WARRANTY, DISCLAIMER OF DAMAGES - Except for the “Right of Replacement or Refund” described in paragraph 1.F.3, the Project Gutenberg Literary Archive Foundation, the owner of the Project Gutenberg™ trademark, and any other party distributing a Project Gutenberg™ electronic work under this agreement, disclaim all liability to you for damages, costs and expenses, including legal fees. YOU AGREE THAT YOU HAVE NO REMEDIES FOR NEGLIGENCE, STRICT LIABILITY, BREACH OF WARRANTY OR BREACH OF CONTRACT EXCEPT THOSE PROVIDED IN PARAGRAPH 1.F.3. YOU AGREE THAT THE FOUNDATION, THE TRADEMARK OWNER, AND ANY DISTRIBUTOR UNDER THIS AGREEMENT WILL NOT BE LIABLE TO YOU FOR ACTUAL, DIRECT, INDIRECT, CONSEQUENTIAL, PUNITIVE OR INCIDENTAL DAMAGES EVEN IF YOU GIVE NOTICE OF THE POSSIBILITY OF SUCH DAMAGE. 1.F.3. LIMITED RIGHT OF REPLACEMENT OR REFUND - If you discover a defect in this electronic work within 90 days of receiving it, you can receive a refund of the money (if any) you paid for it by sending a written explanation to the person you received the work from. If you received the work on a physical medium, you must return the medium with your written explanation. The person or entity that provided you with the defective work may elect to provide a replacement copy in lieu of a refund. If you received the work electronically, the person or entity providing it to you may choose to give you a second opportunity to receive the work electronically in lieu of a refund. If the second copy is also defective, you may demand a refund in writing without further opportunities to fix the problem. 1.F.4. Except for the limited right of replacement or refund set forth in paragraph 1.F.3, this work is provided to you ‘AS-IS’, WITH NO OTHER WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED,
  • 60. INCLUDING BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PURPOSE. 1.F.5. Some states do not allow disclaimers of certain implied warranties or the exclusion or limitation of certain types of damages. If any disclaimer or limitation set forth in this agreement violates the law of the state applicable to this agreement, the agreement shall be interpreted to make the maximum disclaimer or limitation permitted by the applicable state law. The invalidity or unenforceability of any provision of this agreement shall not void the remaining provisions. 1.F.6. INDEMNITY - You agree to indemnify and hold the Foundation, the trademark owner, any agent or employee of the Foundation, anyone providing copies of Project Gutenberg™ electronic works in accordance with this agreement, and any volunteers associated with the production, promotion and distribution of Project Gutenberg™ electronic works, harmless from all liability, costs and expenses, including legal fees, that arise directly or indirectly from any of the following which you do or cause to occur: (a) distribution of this or any Project Gutenberg™ work, (b) alteration, modification, or additions or deletions to any Project Gutenberg™ work, and (c) any Defect you cause. Section 2. Information about the Mission of Project Gutenberg™ Project Gutenberg™ is synonymous with the free distribution of electronic works in formats readable by the widest variety of computers including obsolete, old, middle-aged and new computers. It exists because of the efforts of hundreds of volunteers and donations from people in all walks of life. Volunteers and financial support to provide volunteers with the assistance they need are critical to reaching Project Gutenberg™’s goals and ensuring that the Project Gutenberg™ collection will
  • 61. remain freely available for generations to come. In 2001, the Project Gutenberg Literary Archive Foundation was created to provide a secure and permanent future for Project Gutenberg™ and future generations. To learn more about the Project Gutenberg Literary Archive Foundation and how your efforts and donations can help, see Sections 3 and 4 and the Foundation information page at www.gutenberg.org. Section 3. Information about the Project Gutenberg Literary Archive Foundation The Project Gutenberg Literary Archive Foundation is a non-profit 501(c)(3) educational corporation organized under the laws of the state of Mississippi and granted tax exempt status by the Internal Revenue Service. The Foundation’s EIN or federal tax identification number is 64-6221541. Contributions to the Project Gutenberg Literary Archive Foundation are tax deductible to the full extent permitted by U.S. federal laws and your state’s laws. The Foundation’s business office is located at 809 North 1500 West, Salt Lake City, UT 84116, (801) 596-1887. Email contact links and up to date contact information can be found at the Foundation’s website and official page at www.gutenberg.org/contact Section 4. Information about Donations to the Project Gutenberg Literary Archive Foundation Project Gutenberg™ depends upon and cannot survive without widespread public support and donations to carry out its mission of increasing the number of public domain and licensed works that can be freely distributed in machine-readable form accessible by the widest array of equipment including outdated equipment. Many
  • 62. small donations ($1 to $5,000) are particularly important to maintaining tax exempt status with the IRS. The Foundation is committed to complying with the laws regulating charities and charitable donations in all 50 states of the United States. Compliance requirements are not uniform and it takes a considerable effort, much paperwork and many fees to meet and keep up with these requirements. We do not solicit donations in locations where we have not received written confirmation of compliance. To SEND DONATIONS or determine the status of compliance for any particular state visit www.gutenberg.org/donate. While we cannot and do not solicit contributions from states where we have not met the solicitation requirements, we know of no prohibition against accepting unsolicited donations from donors in such states who approach us with offers to donate. International donations are gratefully accepted, but we cannot make any statements concerning tax treatment of donations received from outside the United States. U.S. laws alone swamp our small staff. Please check the Project Gutenberg web pages for current donation methods and addresses. Donations are accepted in a number of other ways including checks, online payments and credit card donations. To donate, please visit: www.gutenberg.org/donate. Section 5. General Information About Project Gutenberg™ electronic works Professor Michael S. Hart was the originator of the Project Gutenberg™ concept of a library of electronic works that could be freely shared with anyone. For forty years, he produced and distributed Project Gutenberg™ eBooks with only a loose network of volunteer support.
  • 63. Project Gutenberg™ eBooks are often created from several printed editions, all of which are confirmed as not protected by copyright in the U.S. unless a copyright notice is included. Thus, we do not necessarily keep eBooks in compliance with any particular paper edition. Most people start at our website which has the main PG search facility: www.gutenberg.org. This website includes information about Project Gutenberg™, including how to make donations to the Project Gutenberg Literary Archive Foundation, how to help produce our new eBooks, and how to subscribe to our email newsletter to hear about new eBooks.
  • 64. Welcome to our website – the perfect destination for book lovers and knowledge seekers. We believe that every book holds a new world, offering opportunities for learning, discovery, and personal growth. That’s why we are dedicated to bringing you a diverse collection of books, ranging from classic literature and specialized publications to self-development guides and children's books. More than just a book-buying platform, we strive to be a bridge connecting you with timeless cultural and intellectual values. With an elegant, user-friendly interface and a smart search system, you can quickly find the books that best suit your interests. Additionally, our special promotions and home delivery services help you save time and fully enjoy the joy of reading. Join us on a journey of knowledge exploration, passion nurturing, and personal growth every day! ebookbell.com