Remember that all other brokerage services charge you when you open your trade and also charge you when you close out your position. That's $10 for just one round trip--a $5 for opening position and a $5 for closing position. That's a lot of $5(s) and $10(s) to waste.
Please check the following out:
tastyworks.comAnother very good brokerage house that has zero commissions, zero options contract fees, zero deposit minimum. Please check the following out:
Webull.COM There are plenty of other brokerage services that have no minimum -- or if they do, it is very little minimum and the majority of them have a minimum of $25. Some brokers have no minimum but require their clients to keep accounts active by mean of trading. So look around.Article Date: August 9, 2014
By Paul S. Tuon
The total of all those shares (or in the previous example, 400,000,000) is called shares outstanding. All those shares outstanding is called a stock, hence answering the question posed earlier 'what is a stock?'
Notice that a company can have many stocks: common stock, preferred stock and warrants, and each of the three types of stocks can contain classes of their own, such as common stock class A, B, C, etc., Preferred stock class A, B, C, etc.; and each class in those three types of stocks is also called a stock.
Now the answer to the question: 'what is a stock?' is now much clearer.
Different classes of a stock contain different rights and privileges, with the highest rights and privileges given to the highest alphabet order. For example, class A shares have higher rights and privileges than class B, class B shares have higher rights and privileges than class C, class C shares have higher rights and privileges than class D, and so forth.Of the three types of stocks, common stock shares have the least rights and privileges and preferred stock shares have the highest rights and privileges and its classes shares generally have preferrential treatment over all common stock classes shares and also have preferrential treatment over all warrant shares of a stock as well. warrant shares generally have rights and privileges somewhere between common stock shares and preferred stock shares.
A share of a stock whether a common stock, a class A, B, or C, or preferred class A, B, or C, or warrants, represents a part-ownership in the company. A publicly traded company is owned by its shareholders, including the original owner(s) -- often thousands of people and institutions -- each owning a fraction of the whole company.A newly formed company usually requires a "bylaw" written by the founders of the company. The bylaw states the rights and duties of the company, including ownership interest. At a very minimum, the bylaw should issue certificates of stock ownership to the shareholders involved, including the founders and early investors at the inception.
Here is what a typical certificate of ownership looks like:
Certificate Number: 1000
This certifies that Mary Q. Public is the owner and registered holder of twenty thousand
(20,000) shares of ABC Corporation, transferable only on the books of the corporation
by the holder hereof in person or by duly authorized attorney upon surrender of this
certificate properly endorsed.
IN WITNESS WHEREOF, the said corporation has caused this certificate to be signed by
its duly authorized officers of the corporation this 2nd day of October, 2018.
ABC Corporation
by president: ___________________________
John J. Doe
|
shareholders dilution.shareholders dilution: it dilutes existing shareholders' value because there are more shares outstanding and perhaps there are more shareholders in the company. The more shares the company is selling the more dilute value for existing shareholders.| Strike | Symbol | Last | Chg % | Bid | Ask | Volume | Open Interest |
| $15.00 | T100918C00015000 | 7.45 | 0.23 | 7.40 | 7.50 | 45 | 175 |
| $25.00 | T100918C00025000 | 3.45 | 0.04 | 3.40 | 3.50 | 106 | 694 |
| Call Options Quotes |
| For AT & T, Inc (Symbol: T): 07-30-2010: $25.94 |
| Expire at close on Friday September 17, 2010 |
| Strike | Symbol | Last | Chg % | Bid | Ask | Volume | Open Interest |
| $23.00 | T100918C00023000 | 2.94 | 0.23 | 3.00 | 3.05 | 45 | 175 |
| $24.00 | T100918C00024000 | 2.15 | 0.04 | 2.10 | 2.13 | 106 | 694 |
| $25.00 | T100918C00025000 | 1.31 | 0.05 | 1.27 | 1.28 | 138 | 2,924 |
| $26.00 | T100918C00026000 | 0.63 | 0.00 | 0.60 | 0.61 | 322 | 11,331 |
| $27.00 | T100918C00024000 | 0.21 | 0.02 | 0.19 | 0.21 | 466 | 3,637 |
| $28.00 | T100918C00024000 | 0.06 | 0.01 | 0.04 | 0.06 | 120 | 808 |
| $29.00 | T100918C00029000 | 0.02 | 0.00 | N/A | 0.02 | 10 | 20 |
| $30.00 | T100918C00024000 | 2.15 | 0.04 | 2.10 | 2.13 | 106 | 694 |
| Put Options Chain Quotes |
| For AT & T, Inc (Symbol: T): 07-30-2010: Price $25.94 |
| Expire at close on Friday September 17, 2010 |
| Strike | Symbol | Last | Chg % | Bid | Ask | Volume | Open Interest |
| $23.00 | T100918P00023000 | 0.05 | 0.00 | 0.09 | 0.11 | 6 | 1,651 |
| $24.00 | T100918P00024000 | 0.15 | 0.01 | 0.16 | 0.18 | 131 | 1,025 |
| $25.00 | T100918P00025000 | 0.31 | 0.00 | 0.32 | 0.34 | 76 | 3,194 |
| $26.00 | T100918P00026000 | 0.63 | 0.03 | 0.65 | 0.67 | 283 | 1,634 |
| $27.00 | T100918P00027000 | 1.24 | 0.02 | 1.24 | 1.27 | 273 | 1,774 |
| $28.00 | T100918P00028000 | 2.05 | 0.03 | 2.09 | 2.11 | 78 | 439 |
| $29.00 | T100918P00029000 | 3.15 | 0.15 | 3.05 | 3.10 | 89 | 18 |
| $30.00 | T100918P00030000 | 4.15 | 0.15 | 3.95 | 4.10 | 124 | 1 |



In options lingo, selling a "covered call" is called "writing a covered call." There are two steps for this process:
Step 1: Buy the stock for the purpose of selling the right to own the stock to someone else.
Step 2: Sell a call option or writing a call option. Writing a covered call option means that you're giving other investors the "right to buy" your 100 shares of your stock that you'd bought and currently are holding them.
The call option you sold requires you to deliver your 100 shares of the stock if the option is exercised. That can happen anytime between the time you sold and the expiration date of the option. Remember that you need to hold your stock until the option expires.
As of this writing (March 26, 2018), the call option you want to sell is the Citygroup stock quoted for April 27, 2018 (expire in one month) with a strike price of $67.00 for a premium of $3.50 per share. OK, you bought a Citygroup stock at $67 a share and turn around and sell a covered call for the same amount as you bought them.Update: June 25, 2025. Nivdia stock: $154/share. Update: June 10, 2024. Nivdia stock: $121/share. Today, June 10, 2024, Nvidia Corp. begins trading on a post-10-for-1 stock split. From now on the stock base point per share to gauge is $121 per share (and not the pre-split $1,224.40 per share on Wednesday June 5, 2024). This is the second time in less than two years that Nvidia stock is split -- a very good sign that the stock is doing very well. Nvidia's stock closed on Wednesday June 5, 2024, pre-split of $1,224.40 per share. Update: July 14, 2023. Nivdia stock: $481/share (post-splits). Update: June 13, 2021. Nivdia stock: $410/share (post-splits). Update: Remember that Nivdia stock was split on May 21, 2021 and began trading on a post-split of: $194/share. Now (as of June 13, 2023) the stock is worth more than twice the post-split share of $194/share. If you had bought the stock and held it since I recomended: CONGRATULATION!!! Update: July 21, 2021. Nivdia stock: $194/share. Nvidia Corp. today begins trading on a post-4-for-1 stock split. From now on the stock base point per share to gauge is $194 (and not $819) per share. Update: July 2, 2021. Nivdia stock: $819/share. Update: May 21, 2021. Nivdia stock: $598/share. Nvidia Corp. today announced it would split its shares 4-for-1 in an effort to make them more accessible to investors and employees. You can think of a stock split as exchanging a $1 bill for four quarters. The total value is the same; it's just divided into more pieces; or for a reverse split, it's just combines more shares into smaller shares, giving you less shares but not less amount of money that you get. Stock splits don't change the fundamental value of a business. So for a 4-for-1 split is in many ways like exchanging a $1 bill for four quarters. In the end, you get the same amount of money for your stock holding. The split, in the form of a stock dividend, is subject to shareholder approval at the Santa Clara, California-based company's annual meeting on June 3, 2021, Nvidia said in a statement today Friday. The move, if approved, would increase the common stock to 4 billion shares. The shares jumped 3.1% as trading got underway in New York earlier today Friday. Currently Nvidia has about 622.4 million shares outstanding, valuing the company at $363.8 billion, based on Thursday's closing share price of $584.50. The stock has gained 12% so far this year (2021). If shareholders approve the plan, each Nvidia stockholder of record on June 21 will receive a dividend of three additional shares of common stock for every share held, to be distributed after the close of trading on July 19, 2021. Trading is expected to begin on a stock split-adjusted basis on July 20, 2021. Update: October 27, 2020. Nivdia stock: $536/share. The stock is now at $536/share, surpassing my 5-year target of $320 per share. Better yet, this company is growing rapidly in a 'breakneck' speed through in-house inovations and outside acquistions. So the future is very bright. The management is very smart in using their 'skyrocket' high stock price to buy these valuable companies without denting their cash on-hand. That's what you can do when your company's stock is as high as NVIDIA is - it gives you leverage and power to do things that otherwise would not be possible. Nvidia reminds me of Amazon just a few years ago when Amazon stock was already trading around $500 per share and the stock was moving up steadily ever since [February 26, 2016 at $555 per share; October 27, 2017 at $1,100 per share; May 11, 2018 at $1,603 per share; November 11, 2019 at $1739 per share; March 27, 2020 at $1,900 per share; May 29, 2020 at $2442 per share; September 4, 2020 at $3294 per share; June 22, 2021 at $3505 per share]. Let me clarify my view on this comparison: Nvidia is not Amazon nor will it perform like Amazon stock in the future. It will never be anything near what Amazon has done -- no stock is nor will be. However, the strategy that Nvidia employs recently resemblances the strategy that Amazon employed leading up to their current high performances of its stock. The purchase of ARM is a very smart move by Nvidia's management and it will do a lot of good for the future of this company. Will its stock performs like Amazon's stock in the future? We'll see! And time will tell! Here is the synopsis from the press release: Unites NVIDIA's leadership in artificial intelligence with Arm's vast computing ecosystem to drive innovation for all customers NVIDIA will expand Arm's R&D presence in Cambridge, UK, by establishing a world-class AI research and education center, and building an Arm/NVIDIA-powered AI supercomputer for groundbreaking research NVIDIA will continue Arm's open-licensing model and customer neutrality and expand Arm's IP licensing portfolio with NVIDIA technology Immediately accretive to NVIDIA's non-GAAP gross margin and EPS Consideration of $40 billion to be met through a combination of NVIDIA shares and cash
Please see Here is my definition of "dollar cost average": "Stocks rarely go up in a straight line." Just remember that definition when you think of a dollar cost average. Because of the nature of stocks, which rarely go up in a straight line, it makes a great strategy for a long term investment. Update: July 2, 2021. AbbVie stock: $115/share.
Update: July 2, 2020. Nivdia stock: $384/share, surpassing my 5-year target of $320 per share.
Update: November 16, 2018. Nivdia stock: $163/share.
Synopsis: Nvidia Stock Crashes After Earnings Guidance and Cryptocurrency Fears.
Nvidia shares fell steeply after the chipmaker gave weak fourth quarter revenue guidance when it reported third-quarter earnings after the close on Wednesday, November 15, 2018. I call it a "crash" based on from where the stock was trading around $280 to $293 a little over a month ago -- October 2, to be more precise.
NVIDIA today (November 15, 2018) reported revenue for the third quarter ended Oct. 28, 2018, of $3.18 billion, up 21 percent from $2.64 billion a year earlier, and up 2 percent from $3.12 billion in the previous quarter.
"AI is advancing at an incredible pace across the world, driving record revenues for our datacenter platforms," said Jensen Huang, founder and CEO of NVIDIA. "Our introduction of Turing GPUs is a giant leap for computer graphics and AI, bringing the magic of real-time ray tracing to games and the biggest generational performance improvements we have ever delivered.
"Our near-term results reflect excess channel inventory post the crypto-currency boom, which will be corrected. Our market position and growth opportunities are stronger than ever. During the quarter, we launched new platforms to extend our architecture into new growth markets -- RAPIDS for machine learning, RTX Server for film rendering, and the T4 Cloud GPU for hyperscale and cloud."
Capital Return
During the first nine months of fiscal 2019, NVIDIA returned $1.13 billion to shareholders through a combination of $855 million in share repurchases and $273 million in quarterly cash dividends.
In November 2018, the board of directors authorized an additional $7 billion under the company's share repurchase program for a total of $7.94 billion available through the end of December 2022.
NVIDIA announced a 7 percent increase in its quarterly cash dividend to $0.16 per share from $0.15 per share, to be paid with its next quarterly cash dividend on December 21, 2018, to all shareholders of record on November 30, 2018.
NVIDIA intends to return an additional $3 billion to shareholders by the end of fiscal 2020, which may begin in the fourth quarter of fiscal 2019.
What does this mean for long term investors, which I am targeting?
Well, if you already own the stock, don't sell but hold on to it in hope that it will recover and maybe turn a profit in the long run, say, in five years. So don't panick!!!
Another excellent strategy is to buy more at these lower prices, turning it into a "dollar cost average" strategy that works wonderfully awesome over a period of time. That's what I would suggest you do: buy more shares at these lower prices and if the stock drops some more buy some more shares to make the dollar cost average works favorably for you.
Bottom line: the fundamental of the company is very much sound and you should stick to the long term horizon instead of panicking to crashes like this one. Remember that stocks rarely go up in a straight line; so the stock market is like sex: there's highs and there's lows and it feels the best just before it ends too soon and it never last long either. As with sex, you'll just have to keep trying for more to get the most out of it.
Goldman said it remains "Buy-rated on the stock as our view that Nvidia has access to
one of the best growth opportunity sets in Semis and that it has a sustainable
competitive lead within remains unchanged."
"The stock will likely not bounce back right away,
given the severity of the miss," Morgan Stanley said.
Wells Fargo Analyst:
Concerns (and now frustration) over a significant gaming channel inventory burn-off
have materialized ... While we can appreciate that NVIDIA's weak F4Q19 outlook is
impacted by a 1-2 quarter work-down of Pascal mid-range gaming card inventory in the
channel ($600M; assuming no sell-in in F4Q19 as crypto-related dynamics flush through
the channel), couple with a seasonal decline in game console builds, we think
investors will be frustrated by NVIDIA's comments exiting F2Q19 that:
"...we [NVIDIA] see inventory at the lower-ends of our stack...inventory is well
positioned for back-to-school and building season that's coming up on F3Q19..."
Bottom Line: Well, even if we model a strong double-digit growth in DCG next year,
we think there is a high likelihood that NVIDIA will not grow next year.
We are modeling for as such.
The large shortfall in guidance due to a bloated channel due to crypto-currency is in
sharp contrast to the comments around channel inventory from the company at the
last earnings call. Our estimates and target price are going lower.
We remain Market Perform rated.
We are Buyers on weakness.
SunTrust Analyst:
The surprisingly weak Q4 guide appears temporary.
NVDA guided Q4 20% below consensus revs as the company halts 1/3 of gaming segment sales
to flush channel inventory built during the crypto enthusiasm in 1H18.
This badly damages near-term revenue and profits, but Datacenter, Pro-Viz,
and Automotive results support our structural growth view.
Gaming resets our 2019 & 2020 EPS to $7.33 & $8.70 (from $8.18 & $9.59).
PT goes to $237 (from $316) based on 30x (17x discount to rapid-growth tech peers)
our CY20 EPS, discounted back 1 year. Buy.
RBC Analyst:
Going forward, we think the focus will now shift to Data Center as gaming expectations
are now reset due to crypto currencies and a product transition (Turing) which will
unlikely ramp until around the Jul-qtr time frame. Net Net: we lower our price target
due to the lower than expected results (PT to $260 from $310).
Positively, gaming and Pro Visualization will likely be up q/q in January helping gross
margins and offsetting the material gaming weakness.
2. Abbvie Inc (ABBV), stock price on March 23, 2018: $97.46 ===> a drugs maker selling top drugs like Humira, Revlimid, Enbrel, Rituxan, Herceptin, etc. The company announced in February 2018 that it set aside $10 billion for shares buybacks of about 87.6 million shares, or 5.5% of the shares outstanding, starting in May 2018 and continues to the end of the year.
AbbVie Synopsis
The performance of AbbVie (ABBV) shares through 2018 thus far up to June 30th (2018) can be characterized as lackluster. It has performed similar to the S&P 500 and is just above break-even at .8% return on the year. A lot of pessimism is built into the share price relating to two failed clinical tests by Rova T and Imbruvica. The stock market is beginning to question AbbVie's pipeline of 20 drugs and its ability to supplement the massive growth in sales of its Humira drug line.
Humira has been a massive success. It is an extremely profitable drug for AbbVie and it accounts for over 66% of its net revenue ($18.4 billion). The company secured a deal with Samsung Bioepis and partner Biogen (NASDAQ:BIIB) to fend off generics until 2022. It has been developing immunotherapy cancer drugs and is reliant on research and development to internally develop a Humira replacement which will decrease its reliance and revenue concentration risk.
Its second top-selling drug is called Imbruvica. This drug can differentiate between cancer cells and regular cells. It inhibits the growth of certain cancer cells caused by lymphoma and leukemia. Imbruvica will generate greater than $3.3 billion in sales during 2018 and management projects a terminal revenue level of $7 billion in sales in the next few years.
AbbVie is a cash flow machine, it generates $10 billion of free cash flow a year and it consistently increases the capital repatriation to shareholders. The company pays $3.76 dividend per share, which equates to a 3.94% yield based on a closing price of $95.41. This strong cash flow generation has created significant assets and the ability to leverage its balance sheet to make an acquisition to stave off revenue decline from the Humira patent expiration into 2022.
This isn't your typical one drug value trap biotech stock like Gilead (GILD); it has substantial growth opportunities in the pipeline and remains a candidate to make an acquisition.
Summary
Analysts estimate the 5-year revenue compound annual growth rate will average 17%, which is significant for a company with a $146-billion market capitalization. With the 5-year revenue compound annual growth rate on average of 17% should propel the company's market capitalization to around $300 billion or close to it.
This is a very solid company that consistently has increased its dividend regularly at a good percentage. My 5-year target: $200 a share.
As of July 31, 2018, I'm adding a new stock and squeeze it in as the third-rated stock: Texas Pacific Land Trust (TPL). This stock doesn't have options, so you can't use it to trade cash-secured puts and covered calls.

3. Texas Pacific Land Trust (TPL), stock price on July 31, 2018: $740.00 ===> Texas Pacific Land Trust was created in 1888 as a result of a bankruptcy of the Texas and Pacific Railway Company. A company, or more specifically a trust, that is trying to go out of business and ceased to exist.
Why would I or anyone want to invest in a company that is trying to go out of business?
As they say: "... the devil is in the detail."
What exactly is in the detail? Read on.
My 5-year target: $2800 a share -- a 3 1/2 times current price of $740.00 per share.
Update: July 2, 2021. Texas Pacific Land Trust stock: $1593/share. It's Texas Pacific Land Corporation now.
Note (about the WARNING above) that TPL's annual report filed on Form 10-K and Form 10-Q filed in 2020 stated that Texas Pacific Land Trust (TPL) will become Texas Pacific Land Corporation (TPL) on January 1, 2021 -- as it will be converted from a trust to a real corporation called the Texas Pacific Land Corporation.
The trust will cease to exist and a new era begins (on January 1, 2021) as a real corporation called the Texas Pacific Land Corporation from January 1, 2021 and onward.

| Payment Type | Declared Date | Payable Date | Amount |
| Annual Regular Dividend | February 25, 2016 | March 16, 2016 | $.31 |
| Annual Regular Dividend | February 21, 2017 | March 9, 2017 | $.35 |
| One-time Special Dividend | February 21, 2017 | March 9, 2017 | $1.00 |
| Annual Regular Dividend | February 21, 2018 | March 16, 2018 | $1.05 |
| One-time Special Dividend | February 21, 2018 | March 16, 2018 | $3.00 |
| Annual Regular Dividend | February 25, 2019 | March 15, 2019 | $1.75 |
| One-time Special Dividend | February 25, 2019 | March 15, 2019 | $4.25 |
| Annual Regular Dividend | February 24, 2020 | March 16, 2020 | $16.00 |
| Quarterly Regular Dividend | March 08, 2021 | March 15, 2021 | $2.75 (or $11 annually) |
| Quarterly Regular Dividend | June 08, 2021 | June 15, 2021 | $2.75 (or $11 annually) |
| Quarterly Regular Dividend | September 10, 2021 | September 15, 2021 | $2.75 (or $11 annually) |
| Quarterly Regular Dividend | December 07, 2021 | December 15, 2021 | $2.75 (or $11 annually) |
As of January 1, 2021, it's the seventeenth consecutive year that the annual dividend has been increased.
Note that Texas Pacific Land Trust (TPL) has become Texas Pacific Land Corporation (TPL) -- it's no longer a trust, which has been converted into a real corporation called the Texas Pacific Land Corporation.
Note (about the WARNING above) that TPL's annual report filed on Form 10-K and Form 10-Q filed in 2020 stated that Texas Pacific Land Trust (TPL) will become Texas Pacific Land Corporation (TPL) on January 1, 2021 -- as it will be converted from a trust to a real corporation called the Texas Pacific Land Corporation.
The trust will cease to exist and a new era begins (on January 1, 2021) as a real corporation called the Texas Pacific Land Corporation from January 1, 2021 and onward.
This means that the shares outstanding will decrease over time, little by little, while the stream of income just keep coming, driving the stock price higher and higher and higher, hence lands this stock in the third ranking of my pick.Note (about the WARNING above) that TPL's annual report filed on Form 10-K and Form 10-Q filed in 2020 stated that Texas Pacific Land Trust (TPL) will become Texas Pacific Land Corporation (TPL) on January 1, 2021 -- as it will be converted from a trust to a real corporation called the Texas Pacific Land Corporation.
The trust will cease to exist and a new era begins (on January 1, 2021) as a real corporation called the Texas Pacific Land Corporation from January 1, 2021 and onward.
You're among the last lot of shares to be bought out by the trust to cease to exist. At that time, the trust would still have some pieces of valuable land to get rid of and it tries to get the highest bid for the lands. Once the pieces of land are sold, the proceeds are used to buy the remaining lot of shares to close out the trust.Note (about the WARNING above) that TPL's annual report filed on Form 10-K and Form 10-Q filed in 2020 stated that Texas Pacific Land Trust (TPL) will become Texas Pacific Land Corporation (TPL) on January 1, 2021 -- as it will be converted from a trust to a real corporation called the Texas Pacific Land Corporation.
The trust will cease to exist and a new era begins (on January 1, 2021) as a real corporation called the Texas Pacific Land Corporation from January 1, 2021 and onward.
Update: July 2, 2021. Micron Technology stock: $80/share.



A foreign reserve is the foreign currency that a country has in its possession or in its bank vault. For example, China has trillions of U.S. dollars stored in its bank vault. Actually, most of the trillions of U.S. dollars China has on its book are in the form of U.S. Treasury Securities (which it can be turned into U.S. dollars at any time).
That is China's foreign reserve. It's a foreign money it has in its possession or in its bank vault.
Many other countries also hold currencies of other countries as well, particularly the U.S. dollars, as their foreign reserve.
So a foreign reserve is a foreign money a particular country has in its possession or in its bank vault.
Remember that a country typically has its own currency, e.g., the United States has the dollar as its own currency, Great Britain has its own currency called the Pound, China has its own currency called the Yuan, Japan has its own currency called the Yen, the 12 European countries: France, Germany, Italy, etc., have their own currency called the Euro dollar.
For the most part, each currency can be used inside its own country only; for example, the Chinese Yuan can be used only inside China, and likewise, the European Euro dollar can be used only inside the 12 European countries and nowhere else.
When people travel to a foreign country, they have to exchange their own country's currency with of that foreign country's currency.
For example, if you go to China or any other country for that matter, once you arrived at the country's airport you need to exchange your U.S. dollar with that country's currency so that you can use it to buy things while you're in that country. Another example, when you go to France (or any one of the 12 European countries that carry the Euro dollar), you need to exchange your U.S. dollar with the Euro dollar so that you can use it to buy things in those countries.
Likewise, when businesses invest or trade with a foreign country, they have to exchange their own country's currency with of that foreign country's currency.
For example, when Walmart Corporation and other U.S. companies buy Chinese products to sell in their stores in the U.S., they need to exchange their U.S. dollar with the Chinese Yuan so that they can use the Chinese Yuan to buy those Chinese products because the Chinese government barred the use of foreign currencies inside China.
Most countries do this as well, e.g., you can't use the Euro dollar to buy things in the United States either.
When U.S. companies buy products from Chinese companies, Chinese companies take those U.S. dollars and deposit them in their bank accounts in Chinese banks or more specifically in Chinese cenral bank, which is controlled by the Chinese govenment.
And those U.S. dollars, in turn, get converted by the Chinese central bank into Chinese Yuans, giving Chinese companies their actual Chinese currency -- and not in U.S. currency.
Well, most likely U.S. companies need to convert U.S. dollars into Chinese Yuans first and then buy Chinese products using Chinese Yuans instead.
Anyhow, the effect is still the same: China has lots and lots of U.S dollars -- trillions of it!
Japan also has lots and lots of U.S dollars -- trillions of it -- due to its longstanding trading surpluses with the United States for decades and decades.
Among of all the countries of the world, Asian countries have the world's largest holdings of U.S. dollar reserves (in the form of foreign reserve) -- a legacy of the 1997 Asian financial crisis where policymakers fretted about dollar shortages and free-falling local currencies.
In reserve holdings (as of January 1, 2022), China towers above them all with a cash pile above $3 trillion but peer countries in the region have also been formidable accumulators, predominantly in the US dollar. They include Japan ($1.4 trillion), Singapore ($426 billion), India ($604 billion), Taiwan ($550 billion), and South Korea ($457.8 billion).
Like other big economy countries, including the U.S., the Chinese goverment can print money out of thin air without fearing of inflation or de-value(ing) their currency by printing money out of thin air whenever they want.
So to convert the U.S. dollars into the Chinese Yuans, the Chinese goverment can print more Chinese Yuans and credit Chinese companies in exchange for their U.S. dollars.
In effect, China has lots and lots of U.S dollars -- trillions of it!
The United States is notorious in the business of money printing, particularly in the 1929 Great Depression, the Federal-Aid Highway Act of 1956 (which was used to build The Interstate Highway System), the 2008 Financial Crisis (commonly known as The Great Recession), and most recently, the COVID-19 Pandemic Crisis of 2020 (and the aftermath of the COVID-19 Pandemic Crisis).
From January 2020 to June 2022, the United States alone printed $7 trillion and we are not done printing money yet (as of June 2022).
So as a result, both the U.S. and China have lots of money supply floating around (particularly the U.S.), with the U.S. Federal Reserve printing money supply to buy bonds sold by U.S. companies; while China has trillions of U.S. dollars (and other country's currencies as well) on its book because of the trade surpluses with other countries, particularly the United State.
All of these events (the money printing and exchanging of currencies) create a system of foreign reserve.
This system of foreign reserve, particularly, the exchanging of currencies is called the foreign exchange market.
A foreign exchange is a place where you can exchange your currencies for other currencies. It is like a stock exchange but instead of buy stocks, you buy other currencies using your own country's currency to buy other countries' currencies.
If you travel to other countries, you exchange your U.S. dollars using the foreign exchange market, which physically handles the exchange of the currencies.
Trades are the main source of the foreign exchange market (i.e., Walmart buying Chinese goods), causing each country's currency to fluctuate (or rise/fall in value) according to the supply and demand of the currency.
For example, the U.S. dollar is typically in high demand by traders all over the world and therefore it is more valuable than other currencies.
Keep the supply/demand principle in mind when you deal with the foreign exchange market, because it is based on the supply and demand of the currencies involved in the trade or exchange.
This trading of currencies in the foreign exchange market is where countries are so worried/abcessed with the concept of foreign reserve--they have to!. Their economy depends on it!
The answer to that question may surprise you and may even put you on edge if you're from a country that has low foreign reserve.
Two examples that come to mind is in 1992 when George Soros broke the Bank of England and another occurred in 1997 during the Asian financial crisis, particularly in Thailand after the Thai baht plunged in value.
Now we're on to the description of the foreign reserve concept in depth.
I'm little lazy, so I'm going to refer you to some excellent tutorials on the Web, which can explain better than I can.
As you watch the following videos, keep the trading of currencies in the foreign exchange market in mind because it is all about trading of currencies.
Also, don't forget to keep the supply/demand principle in mind as well.
To understand the concept of foreign reserve in depth, you have to at least finished watching the third video in the list below. The first two videos are just introductions to warm you up for the concept of the foreign reserve. Here are the video tutorials:
A SPAC (Special Purpose Acquisition Company), also known as a "blank-check" company, is a publicly listed company with no operations that raises money from investors via an IPO for acquisitions.
SPACs raise funds in an IPO to acquire a private company, which then becomes public as a result of the merger.
In other words, SPAC firms raise capital through an initial public offering with the intention of using the cash to acquire a firm and take the merged entity public.
A SPAC has no commercial operations, but exists solely to raise money by listing on the stock exchange, with the hope of finding and buying a profitable and fast-growing company to acquire. After the SPAC lists, it has a set time period in which to buy a target private company.
Typically, when you start a company you have some sort of products or services to offer to your consumers or clients. The normal process is that you would file a registration to begin the start of your company to begin the process of the "on going" business activities.
Once you're approved of the application, then you can begin the process of the "on going" business activities, such as building/creating products or services.
Most companies start out at its inception as a private company and later after the company has gained a foothold in the business world or be well-known and well-established in the business world as a well-respected company then it might want to go public in the form of an IPO.
In a SPAC, you file the registration to go public [the same way a well-established company does] as if you had gained a foothold or be well-known and well-established company already, and having some products or services to offer to your customers or clients. But in fact, you don't! No products or services! None! Just a blank-check company applying to list on the exchange for the public to own some shares.
Since the prospect or promise of buying a very good and profitable company to merge with [this blank-check company] is so enticing, many big pockets investors pore their abundance of money on the blank-check company hoping to get rich quick. And a lot of them have gotten rich, very rich, in fact!
Never mind that, you have a newly registered publicly traded (IPO) company that contains/has nothing - and never mind that this "blank-check" company only words of assurance is the promise of looking to acquire a good and profitable private company to merge with. Never mind all that -- big and small investors alike jump at the chance of making quick bucks.
Once it is registered as a SPAC and listed on the exchange as a publicly traded IPO company, you can go out and raise funds from investors and then use those funds to acquire a private company, and merging the acquired company with the blank-check company to form the combine (two) companies as one publicly traded company.
In the two years (of 2019 and 2020) we have seen market favorites including Virgin Galactic, DraftKings, and Nikola go public through such deals.
Blank-check IPOs exploded in 2020 as firms looked to take advantage of a surge in participation from retail investors and hopes for an economic recovery. More than $74 billion has been raised across 218 SPAC debuts in 2020, according to data from SPACInsider.com. That compares to just $13.6 billion raised across 59 deals in 2019.
To answer that question, let's go a little deeper into the detail of SPAC.
Here is an article that appeared on March 30, 2021 by POLITICO. We'll come back to my SPAC details after the article.
The shell companies (or holding companies or companies containing nothing -- or SPACs) that many private firms use to go public on the country's stock exchanges have been all the rage on Wall Street for more than a year (specifically 2019 and 2020). Now, just as their explosive growth shows signs of waning, they are coming under scrutiny from lawmakers and regulators.
Special purpose acquisition companies, or SPACs, which have no business operations and whose only purpose is to acquire a private company to then list on an exchange, have become so popular that they have outstripped traditional initial public offerings. The attraction of these so-called blank check companies, which have been backed by everyone from Shaquille O'Neal and A-Rod to Serena Williams? They get to bypass the costly IPO process, where companies must undergo vetting by the Securities and Exchange Commission before they can sell stock.
Now, lawmakers and consumer advocates are increasingly raising alarms about the risks facing unwitting investors, particularly retail buyers who might not be able to spot a bad deal on their own. And the SEC, which has been pressed by investor advocates for months to take steps to protect investors, is moving in.
"You shouldn't be able to use a SPAC to evade the disclosures and liabilities inherent upon taking a company public," said Rep. Brad Sherman (D-Calif.), chair of the House Financial Services subcommittee that oversees capital markets and investor protection.
Sherman said he thinks "a chunk" of companies are using the process to do just that, a concern shared by other Democrats on the committee, including Rep. Bill Foster of Illinois.
The SEC is looking into potentially illegal activity related to SPACs, according to people with knowledge of the inquiry. The probe was earlier reported by Reuters, which cited letters from the SEC to banks and other underwriters asking about their SPACs activity related to these offerings.
A banker familiar with the situation confirmed to POLITICO (the author of this article) that the SEC had sent a letter to the bank. Another banker said their company was aware that letters were going out on SPACs and that a probe is taking place.
The SEC declined to comment. But the agency this month issued a statement calling on investors to ignore celebrity endorsements of these vehicles. That came after earlier warnings from the regulator, including an investor bulletin in December -- "What you need to know about SPACs."
But just as policymakers and the SEC move to investigate, the performance of these companies appears to be faltering, according to data tracking their performance on the New York Stock Exchange and Nasdaq.
Data on SPAC performance 30 days out from a deal to take a private company public show the companies are performing worse on average in 2021 compared to 2020. While investors continue to show keen interest in buying stock in these SPAC shells before a deal, the declining performance suggests that finding a good deal to take a private firm public could be getting more difficult.
That could be a problem given all the new companies that are out there looking for deals.
Less than three months into 2021, SPAC IPO activity has already surpassed all of 2020, the year that the investment vehicles took up roughly half the market for new public company listings, in terms of deals and dollars raised. By comparison, the previous peak was 14 percent of the market in 2007, according to research firm SPAC Analytics.
Behind the surge is the prospect of a good deal for those who get in early, usually large, institutional investors. SPACs generally list on public markets with the proviso that they must acquire a private company in two or three years with the help of a sponsor who collects fees for a successful deal. That's when it tends to draw lots of small investors. If the SPAC fails to bring a private company public, it must return the money to investors, making the potentially lucrative investment appear relatively low risk.
But advocates fear many of these newly established companies will be under pressure to strike a bad deal instead of none at all, so early investors get a big return, sponsors get their fees and then retail investors take the loss when share prices plummet.
"Now all of a sudden, you own a garbage company," said Andrew Park, senior policy analyst at Americans for Financial Reform, a progressive investor advocacy group that has been warning policymakers for months about the dangers of SPACs.
Combined with growing animosity - particularly from private equity - toward the rigors of the traditional public offering process, interest in the companies soared along with the rising stock market. That has fed concern that there's a bubble ready to pop in SPACs.
"One of the clear dangers here is that there are going to be too many SPACs, chasing too few merger targets, that we're going to see some truly bad deals struck," said Foster, the Illinois Democrat. "This boom will just cause them to scrape the mud off the bottom of the of the pool."
Companies consult with the SEC when putting together the proxy and registration statements to take the private company public, and the agency can comment on their drafts. If there are enough shareholder votes to approve the acquisition, a financial disclosure to the SEC is then required of the combined entity. But during the initial listing process, a SPAC has little to offer except the promise of big future plans. That's a major reason why it has been so easy for them to crop up on public exchanges.
From January to mid-March (2021), there were 264 SPAC offerings on the Nasdaq and the NYSE raising $76.8 billion, according to a POLITICO analysis of listing data for the nation's two largest exchanges. That eclipsed traditional IPOs, which had just 74 deals and raised $30.1 billion over the same time period.
"The SEC's been warning investors now for months about the risks of SPACs, but that hasn't made a dent," said Tyler Gellasch, executive director of investor advocacy group Healthy Markets Association. "I expect the SEC and Congress are going to try to pop the speculative bubble soon, and a quick way to do that would be to restore some basic liability on those involved in the deals."
Proponents of SPACs say the transactions offer retail investors the chance to see bigger returns that might otherwise be reserved for the private market. They also view the boom in public offerings as positive for the market, regardless of whether companies fail, because it means more businesses are going public and providing financial disclosure to the SEC.
Those supporters include U.S. climate envoy John Kerry, who earlier in March said the investment vehicles are valuable because they could help finance green energy companies - a remark that drew a sharp rebuke from AFR.
"They provide spectacular windfalls for insiders while performing very poorly for most investors. They're not the solution to the climate crisis," AFR said in a tweet directed at Kerry.
Republican SEC Commissioner Hester Peirce has warned against regulating the new offerings too quickly. Doing so could reduce the cost-effectiveness of SPACs, she said this month during a meeting of the SEC's Investor Advisory Committee.
"Let's certainly look at what's going on, and try to get our arms around what's going on. The 'why now' questions I think are good questions to ask," Peirce said in an interview. But "we need to appreciate the potential for SPACs."
AFR and the Consumer Federation of America want policy changes that would require more disclosure and ensure legal protections for investors. The groups also say the SEC should conduct more research into what kinds of investors bear the most losses when these companies fail.
Carson Block runs a hedge fund that has bet against companies going public through SPACs, citing research on flimsy company fundamentals. But his warnings have been met with resentment from retail investors.
"This is clearly a situation in which unsophisticated retail is being preyed upon," Block said. "It's because there's euphoria, it's because the markets are being artificially stimulated, and I have seen this movie before, most closely in the late '90s to 2000s Internet bubble. The cure for it is to learn hard lessons."
John Jenkins, a veteran corporate lawyer, said regardless of what regulators do, the boom reflected a fundamental problem in the market.
"You can hammer on the disclosure side, you can hammer on making sure that the conflicts of interest are out there and laid out, but these things are prospering because there's kind of something wrong with the IPO process in general," he said.
But Sherman said the demand is a sign that regulators need to focus on the issue more.
Many companies "don't like the process of going public," the California lawmaker said. "If we can protect investors and make it easier to go public, that's what we should do. But, on the other hand, you don't need a backdoor that evades all of our efforts to protect investors."
[END OF POLITICO ARTICLE]
NOW ONTO MY SPAC IN-DEPTH DETAILS
Remember when you played card games with your brother, or sister, or cousin? Or maybe your son or daughter?
At some point they would have to use the bathroom, or get a drink of water, and bam! When no one was looking, you had your chance to stack the deck for the next round.
That's 4 aces or a royal flush in five card hold'em. Of course I could never keep a straight face afterward.
Several new SPACs have stacked the deck for their "founders" and warrant holders. And they're not joking around and always keeping a straight face before, during, and afterward while at the same time laughing all the way to the bank.
SPACs (or Special Purpose Acquisition Companies) (also known as Blank Check Companies) organize as if they were part of the fashion industry.
Nowaday (particularly 2021), you couldn't read a business article without coming across SPAC mania. SPACs have been all the rage on Wall Street for more than a year now (specifically 2019, 2020, and into 2021).
Someone comes up with the latest hot color to wear, or style of shoe, and then you see it everywhere.
SPACS are no different. Some underwriter, or attorney, will come up with a tweek to make the structure different.
"We're going to do one-half warrant per unit, in order to minimize dilution," etc., etc., etc.
Then every SPAC after that does one-half warrant per unit - and everybody jumps on the "copycat" bandwagon and everything is catching on like wildfire. As long as the rules are followed for the overall structure, nobody really cares.
The offering to sell SPAC units to the public is typically advertised in a press release that looks like the following:
NEW YORK, Aug. 24, 2020 /PRNewswire/ -- Far Point Acquisition Corporation (NYSE: FPAC.UN) a special purpose
acquisition company, announced today that it is offering 23,000,000 units (including 3,000,000 units granted
to underwriters' over-allotment option in full) at $10.00 per unit, resulting in gross proceeds of $230,000,000.
The units will begin trading on the New York Stock Exchange Capital Market ("NYSE") under the symbol
"FPAC.UN" on November 13, 2019.
Each unit consists of one share of Class A common stock and one-third of one warrant.
Each whole warrant is exercisable to purchase one share of Class A common stock at a price of $11.50 per share.
Only whole warrants are exercisable. Once the securities comprising the units begin separate trading,
the Class A common stock and warrants are expected to be listed on the NYSE under the symbols "FPAC" and "FPAC.WS,"
respectively.
What the Newswire press release is saying is that this SPAC is announcing to the general public
that it is selling "Units" of the SPAC to anyone interested in buying the Units.
Each unit consists of one share of Class A common stock and one-third of one warrant -- meaning,
you buy one Unit at a price of $11.50, you get one share of Class A common stock and
one-third of one warrant.
So you have to buy at least three Units to make your warrant worth one whole warrant,
which can be exchange for one share of Class A common stock.
Just to be clear, I'm speaking from a trading perspective. I have not done an exhaustive study of SPAC structures and how they benefit shareholders / investors, etc.
Bottom line, once a fashion is established in SPAC IPOs it tends to stick. But for how long will the fashion can sustain its attractiveness? According to the POLITICO article above, a bubble looms on the horizon.
When I think of a "founder" I think of the guy or gal who is working 18 hours a day to get a business off the ground. Basically someone who has put in some sweat equity - someone who has some ideas to make things happen.
But I'll turn it over to the experts. This is what Forbes has to say:
Founder is a label with some amount of prestige. It carries connotations of creativity and innovation, determination, native intelligence, and a sense of fearlessness. Founders create something from nothing.
And they go on to add:
Strictly speaking, in business the founders are the people who establish the company -- that is, they take on the risk and reward of creating something from nothing.
You may ask, if we're talking SPACs, a pool of money raised from investors to buy an existing business, then why the talk of founders? Founding what?
There have been countless SPACs gone public to much fanfare, and it turns out, they have added a new fashion statement: founders shares.
The first prospectus I saw mention founders shares (and there are already others) was for Far Point Acquisition Corporation. Even if you don't follow SPACs, you may have heard of this one.
It made some mainstream headlines because it is being led by former NYSE head, Tom Farley. According to a Bloomberg article (not included a link here), Mr. Farley did a lot to make SPACs easier to list.
Given that I hadn't seen founders shares before in a SPAC, I was intrigued. I assumed it was a new way to pay management of the SPAC a little extra money. Nothing out of the ordinary there.
And, the structure is fairly simple. Some "founders" provided money to the fund to set it up in return for stock. In this case it is class B stock, which is convertible into class A stock when the SPAC actually buys another company.
Class A stock is the common stock that the public got in the stock offering. OK, again, nothing earth shattering.
Then I started looking at the numbers. My first thought was, "holy expletive expletive Batman!"
My next thought was, "this SPAC is going to complete an acquisition, or somebody's getting kneecapped."
If the SPAC, for whatever reason, cannot do an acquisition (can't find the right company, the shareholders don't like the deal, etc.) then the SPAC warrants become worthless. Zero, nil, zilch, zip, nada, none.
This makes SPAC warrants somewhat like a lottery ticket. They are either worth something (a deal is announced, then approved) or they are worth nothing (no deal, SPAC dissolved).
It follows that anything that influences whether a deal is more or less likely impacts the value of the warrants.
Now let's talk numbers.
The "founders" of Far Point Acquisition Corporation (which includes Dan Loeb and his hedge fund, Third Point) put $25,000 into the fund which before that "had no assets, tangible or intangible."
No, I didn't leave off a zero on that, it's twenty-five thousand with a T. (So you don't have to come back and reread it.)
So what do you think the founders get in return for that $25,000 if an acquisition is done? How about a 10X return? That's pretty good, but come on, you're a Wall Street insider here, think bigger.
100X? Now we're talking. Show me the money! (that credit card commercial has totally messed up the Jerry Maguire reference). But no, wrong again.
OK, here I'm going to make an assumption. I'll make it quick, stick with me. The Units went public at $10 a share.
The units include one share of common (class A, or what our class B can be converted into) and one-third of a warrant. (Even half-warrants aren't fashionable this year.)
Some of the warrants were sold in a private placement (more on that below) at $1.50 per warrant.
For those of you who are not familiar with warrants: A warrant is like a stock option where you have the right to convert the warrant units into real common stock (usually class A) shares. And some of the warrants are traded publicly on the stock exchanges and some are privately sold in a private placement depending on when the warrant gains a public listing.
So if the Units went public at $10 a share and a warrant costs $1.50 per warrant at a private placement, and that warrant can be converted into class A common stock at $10 a share, you can do the math yourself as to how much money you make [with hands over fist].
So, I'm going to put the value of a share of common stock (A and B are equivalent for this purpose) at $9.50 per share ($10 minus $.50 for one-third warrant).
So, where does that get us? OH YEAH, how many shares of common stock did the "founders" get for their $25,000?
In March 2018 the founders got 11,500,000 shares of stock. Hang on, don't do the math yet.
Because in June 2018, before the SPAC came public, before it had identified or acquired a company .... basically before it had done anything, the "founders" paid themselves a stock dividend.
TWO dividends in fact. The result, the founders received 15,812,500 shares for their $25,000.
Yeah, me too. I can only guess at what was said in the discussion to do the stock dividend.
Maybe, "We just got Mr. Farley from the NYSE to sign on to lead this thing. Who's going to question ANYTHING that we do. Another scotch Jimmy, and what the hell, let's pay ourselves a stock dividend."
Whatever the discussion, at $9.50 a share, the founders are looking to make $150,218,750 (minus their $25,000 investment, I'm not even going to bother subtracting that). BTW, that's over 6,000X their original investment. Hey guys, can I be a founder next time, please, please, please, please?
BUT, remember, they only get this money if Far Point actually acquires a company. So ... my bet is they WILL acquire a company, and the Far Point warrant is going to be a winning lottery ticket.
Far Point added a few additional incentives to make sure a deal is done.
First, the founders have agreed to vote for a deal if a target is selected. Those founders are swell guys.
Remember, if a SPAC selects a target, the SPAC must still put it to the shareholders to vote whether they want to do the deal or get their money back. The Far Point Structure, in which the founders own 20% of the SPAC, means they only need a little over 32% of the shareholders to vote favorably.
Well, at least the founders didn't evade the democracy process in approaching this thing. The founders adhered to the democracy principle by allowing majority opinion wins.
So let's do the math: 20% + 32% is 52%. That's a majority opinion and anything above 50% is a majority opinion. This is a democracy principle.
But the founders don't have a majority opinion on their 20% holding -- do they? Read on!
Second, Third Point agreed to purchase 9,766,667 warrants (presumably at no more than 25 cents per Unit -- hey, you're the buyer and seller -- buying and selling to yourself, and thus, you can set whatever price you want).
These newly purchased warrants are addition to Third Point's original stake in the founder shares, and if no deal is done all these warrants will go to zero.
Third, there is an agreement between Third Point (or Cloudbreak Aggregator, an affiliate of Third Point in the Cayman Islands) and the SPAC, that Third Point will purchase shares of the SPAC which are redeemed by public shareholders.
Remember that SPACs are funded and owned by public investors -- big or small. And if these investors don't like the deal they can sell their SPAC shares in the public market.
Basically, if enough of the public shareholders don't like the deal and want their money back, Third Point will purchase those shares and vote them for the deal. YEAH! RIGHT! The rich get richer!
Fourth, and finally, I've pointed out having a single owner of a block of SPAC shares may make a deal more likely. In other words, you look to attract enough big pocket investors so that you can convince them to vote for the deal because big pocket investors can sway the voting scale quickly as appose to small investors where you need lots and lots and lots of them to vote in favor to sway the outcome of vote.
If that owner has experience with special situations and arbitrage even better. In other words, you can do a backroom deal with that big pocket investor by promising them lucrative terms on the deal and get that investor to vote for the deal.
If we could pick one person to want to own our SPAC shares, and add more likelihood of a deal, it might be this guy, Daniel Och. Who better than a former Goldman Sachs risk arb guy. Mr. Och and his funds have purchased 15,000,000 of the Far Point units.
Given all the various structures that comprise the Far Point Acquisition Corporation, this SPAC IS going to acquire a company. One of the main risks in owning SPAC warrants prior to the announcement of an acquisition is that if the SPAC does not do a deal and the warrants go to zero. That will not happen here. (This article was written in 2019)
Update on Far Point Acquisition Corporation
Here is a press release from Far Point Acquisition Corporation: August 24, 2020
NEW YORK, Aug. 24, 2020 /PRNewswire/ -- Far Point Acquisition Corporation (NYSE: FPAC, FPAC.UN, and FPAC.WS) a special purpose acquisition company ("FPAC"), announced that its stockholders voted to approve the proposed business combination transaction (the "Transaction") with Global Blue Group AG ("Global Blue") at a Special Meeting held for this purpose on August 24, 2020. Holders of 53,505,646 shares of FPAC's Common Stock, or approximately 67.68% of the issued and outstanding shares, voted in favor of the Transaction. The parties expect the closing of the Transaction to occur August 28, 2020. FPAC also announced that stockholders holding 48,708,994 shares of FPAC's Class A Common Stock have elected to redeem their shares in connection with the closing of the Transaction.
|
|
Tesla can issue more stock to sell to the public and use that cash to pay off the bondholders. But having stock prices higher benefit Tesla because Tesla can sell less shares to earn more cash. On top of that, if Tesla's stock is higher than$359.87 Tesla doesn't have to issue more shares to sell -- they can just elect to convert the bonds into shares of Tesla's stock.
So having Tesla's stock stay high has many benefits to Tesla and that's why Wall Street was speculating that Musk's motive was to drive up Tesla's stock when he tweeted about taking Tesla private.
Now in about two years later, Tesla's stock was trading above $2,000 in July and in much of the early August of 2020, making the convertible bonds talk above a moot point or non-issue.
In other words, Tesla and Elan Musk won the battle against critics particularly short sellers who bet against him and his company and lost their shirts to the tune of $38 billions in 2020 alone.
And my gosh, Elan Musk won big against his critics and at the same time propelled himself to the tune of being the richest people on earth (worth $194.8 billion as of January 7, 2021), beating Jeff Bezos ($185.8 billion) of Amazon for the top spot.
Update: August 12, 2020. Tesla stock came down to earth to: $1,374/share after Tesla's stock price climbed above $2,000 recently.
On August 12, 2020, Tesla announced a five-for-one stock split set to take effect at the end of August 2020 after Tesla's stock price climbed above $2,000 recently.
Every Tesla shareholder will receive four additional shares for every share they currently own when trading ends on August 28, 2020, the company said in a press release. The value of all five shares will equal the stock's pre-split closing price from that same day.
Trading of Tesla shares on a split-adjusted basis will begin on August 31, 2020, and is expected to be right around of Tuesday's (August 11 2020) closing level, in which the newly split shares would be worth right around roughly $274 each. The split alone won't change Tesla's market cap. Yet cutting the barrier to entry for smaller investors to buy in could boost Tesla's share price.
Update: December 31, 2020. Tesla stock: $706/share up from the post split of $274 a share on August 28, 2020.
So everything with yield curve has to do with bond yields -- and bond yields have to do with the economics principle supply and demand.
The higher the bond yield, the lower the demand for that bond. Likewise, the lower the bond yield, the higher the demand for that bond.
Say what? The higher the bond yield, the lower the demand for that bond? Does it make any sense?
Take it this way: When you see stores with advertisement that says something like 30% off, 40% off, 50% off, or 60% off, they're telling you that their products are not in high demand and to get rid of those products, they have to lower prices to entice customers to buy them.
Bonds work the same way: When there are lack of demand for the bonds, their yields are typically higher because seller(s) of those bonds will offer bond buyers with higher interest rates to entice bond buyers to buy those bonds; and therefore, making those bonds having higher yields. Make sense?
So the yield curve is the graph that plotted the bond yields. Economists use charts and graphs to interpret the activities of the economy and bond yields is a very important key that drives economic activities.
In the graph illustrated below shows the yield curve for the 10-year bonds, and it is not upward slopping, but rather, it is flattening, which means that the demand for 10-year bonds are in high demand, driving their yields down, hence the flattening of the yield curve. In other words, people are buying more 10-year bonds than they're buying 2-year bonds.
The bond market is a great predictor of future economic activity and future levels of inflation, both of which directly affect the price of everything from stocks and real estate to household items.trending toward zero, or flat. See the graph below:
The horizontal line that has number 0 (zero) can be viewed as the benchmark 2-year bond yield (for easier interpretation). It is actually a line representing maturity dates, however. A 10-year bond is plotted against this horizontal zero-line with varying maturity periods.
If the plotted graph representing a 10-bond goes below zero -- an "inversion" in which the yield on the two-year bond would be greater than the 10-year -- that traditionally signals something is very wrong in the market.

If you ever wanted to learn how to program computer programs, particularly learning how to build a website of your own, this tutorial helps you get started and points you in the right direction to achieving your programming goal. This tutorial is not meant to teach you everything about how to program, but rather, a 'get started' guide that guides you in the right direction to help you get started.
For a complete and specific area of programming, such as a particular language you are interested in learning, please check out tutorials on the Web by Googling it. There are lots of free tutorials on the Internet, particularly YouTube.com and the HTML as noted in the following.
A good place to get started is the W3Schools
And here is another good place to get started:
Learn How to Code OnlineAnd here is a forum for the above site where you can ask the experts on programming topics:
Learn How to Code Online: Codecall Programming Forums!As listed in the W3Schools mentioned above, you need to start with HTML and CSS first, and then proceed to server-side languages such as PHP and then to the client-side languages such as Javascript, and then you should learn databases as well, such as PDO and MySQL, and then to specialized languages such as jQuery and Ajax, in that order. So the order you should follow is: HTML, CSS, PHP, Javascript, PDO, MySQL, jQuery, Ajax.
Also as a programmer, you should also get yourself familarized with CURL as CURL is one of the core technologies that is a "must know" for any programmer, if you're going to be able to program interactive applications effectively.
CURL is an interactive client-server technology (or model) that enables you to make request/response to and from the client and server. In other words, in a client-server model, you use a client-side language like Javascript to send a request for content stored on the server and you use a server-side language like PHP to send the content back to the client. So this is called a request/response or client-server model.
cURL stands for client URL.
For more on CURL, please Google it and start from there.
If you have time, you should learn DOM as well. For an introductory course on DOM, see chapter 3 to 7 of my Ajax book called Introduction to Ajax.
If you mastered all the languages mentioned above, you should be able to build any sophisticated Web applications easily. After that, if you want to learn other languages as well, then you should learn those languages listed in the W3Schools mentioned above in no particular preferential order guideline.
W3Schools above listed category under Javascript, which includes Node.JS and other excellent server-side languages as well, but you really only need to learn PHP is enough for a while. PHP is the most popular server-side language out there, but Node.JS is getting more popular as it is very good in streaming applications, such as movie shows and other live streaming applications.
However, you can accomplish the same thing using PHP, but it is easier to program streaming applications using Node.JS than PHP as Node.JS is specifically built for streaming applications.
If you want to learn how to program sophisticated desktop applications, start with Java, and then C++, and then either Python or C# (pronounce 'see sharp') or even Delphi if you dear to venture into the deep end of the programming language world. But the first three or four listed above is sufficient and you can accomplish any sophisticated desktop applications just fine.
If you just want to learn only one desktop language, Java is a very good choice to learn.
If you dear to venture into the deep end of the programming language world for desktop, here is a link to an excellent language called Delphi
Furthermore, if you dear to venture into the deep end of the programming language world for desktop and for cross-platform mobile applications such as building apps for smartphones (i.e., iOS and Android platforms) using Delphi, here is a link to an excellent tutorial titled: Building your first Native Mobile Applications for iOS and Android
Typically, you would need to find an iOS platform SDK to build your iPhone mobile applications that can run on an iOS platform and then you would need to find an Android platform SDK to build your mobile applications that can run on Android platform.
With Delphi mobile platform, you can build both iOS and Android mobile applications using only one SDK platform. This is very convenient and powerful and not to mention the simpicity of having to learn only one platform for building cross-platform mobile applications.
Again, if you dear to venture into the deep end of the programming language world for both desktop and mobile, start with the free and full-featured Community Editions of Delphi and C++Builder. Community Editions of Delphi and C++Builder are designed to help you get started programming. These powerful IDEs provide all the features you need to quickly explore robust app development.
When Community Edition launched it made all the features of the Professional Edition of Delphi and C++Builder free to students and hobbyists in the community: including mobile platforms, desktop database, and the full source code for the runtime libraries. Now the 10.4.2 Sydney update brings the absolutely latest features and updated platform support to Delphi & C++Builder Community Edition.
There's no better way to build powerful native applications for iOS, Android, Windows, and macOS from a single codebase than using the robust and easy-to-learn Delphi language. This makes it the ideal choice for students or anyone who just wants to get things done.
C++Builder is your choice if you want to master the mysteries of the curly brace (see illustration below). It unlocks a huge variety of C++ standard libraries, while still giving you access to the powerful runtime libraries included in Delphi. This is a winning combination for C++ development.
Note that in Delphi, the syntax is slightly different than with other languages, for example, in other languages you use curly braces or brackets '{}' to group your block of code, such as the beginning and ending of a block of code. For example:
In other languages:
class MyClass
{
public function aMethod()
{
// code block
if (true)
{
//code block
}
}
}
In Delphi:
Type
TMyClass = class
public
class function aMethod()
begin
// code block
if (true)
begin
//code block
end; // end if (true) block
end; // end function aMethod()
end; // end class TMyClass block
// Notice that in Delphi it uses keywords 'begin' and 'end', followed by a semicolon ';', to seperate
// between blocks.
// Note also that in a main program (not shown here) the final 'end' should be a period '.' instead of
// a ';' to end the whole program.
The Community Editions of Delphi & C++Builder are designed for students and hobbyists. If that is you, and you are new to programming, then download the free Community Edition of your choice [Delphi 10.4.2 CE or C++Builder 10.4.2 CE] and register for the free Learn to Code Summer Camp.
Community Editions are available free of charge to developers, and organizations with fewer than five developers. Here are the download links Start Learning Delphi for Free: Delphi & C++Builder FREE Community Editions Start Learning Delphi for Free: Download the FREE Delphi Community Edition Start Learning Delphi for Free: Download the Free C++Builder Community Edition
If W3Schools doesn't have the topics I mentioned here, just Google around and you'll get plenty of results for you to get started. The same thing is also true for begining Delphi programmers: Just Google around and you'll find plenty of resources to get you full speed learning Delphi. Have fun learning!
Here are the steps on how to get started programming for beginners:
First, you need an editor to write your programs with. There are lots of free editors on the Web such as NetBeans IDE, a free, open-source Integrated Development Environment for software developers, particularly for desktop applications. You get all the tools you need to create professional desktop, enterprise, web, and mobile applications with the Java language, C/C++, and even dynamic languages such as PHP, JavaScript, Node.JS, Groovy, and Ruby.
NetBeans IDE is easy to install and use straight out of the box and runs on many platforms including Windows, Linux, Mac OS X and Solaris.
So if you are interested in learning to program desktop applications and as well as Web applications, NetBeans IDE, unlike many other editors mentioned below, is suiteable for both applications.
Other text editors that are very popular among beginners are Notepad++, Sublime Text, Atom, Ultra Edit, TextMate, BBedit, MAX's HTML Beauty++, etc. Please Google them to learn more about them. Or you can just Google the term 'free text editors' and you'll get a bunch of results.
Personally, I have been using two text editors simultaneously: one is NetBeans IDE because I need to compile and run programs written in Java for desktop applications and another is MAX's HTML Beauty++ for doing non-desktop applications for the Web, such as Javascript, Node.JS, HTML, CSS, etc. MAX's HTML Beauty++ is perfectly suitable for these Web languages.
As noted above, MAX's HTML Beauty++ is only suiteable for building Web applications and NetBeans IDE is suiteable for both desktop and Web applications.
What I like about MAX's HTML Beauty++ old version is that it color-codes all PHP code in yellow and leaving all other programming languages code as a default color, which is a non-color black and white.
Using MAX's HTML Beauty++ old version, you can preview your webpages instantly while you're still building it by switching back and forth between a "preview" and an "edit" mode. This is a great feature for beginners trying to learn how to program Web applications.
If you are not into building sophisticated desktop applications, here is MAX's HTML Beauty++ download that will do the job just fine for building Web applications.
The download above is an older version, which happens to be my favorite version that I am still using it to this day, and I prefer this older version over the newer version, which is a 2004 version. If you prefer the newer 2004 version, here it is: http://www.htmlbeauty.com/bsetup.exe download
As a matter of fact, any text editor, including Microsoft NotePad that comes with your Windows operating system, will do just fine for building Web applications.
Also all these downloaded text editors come inside an archive compression zip file. You need to extract them once you've downloaded them using any archive unzip application. There are lots of free archive zip applications available on the Internet. See the following.
Once you've downloaded your favorite text editor, including my favorite text editor MAX's HTML Beauty++, extract it using free zip extracting applications like WinZip ZIP Extractor Express Zip WinRAR or WinRAR here! PeaZip
The archive zip application is a compression program that compresses the content into a small version of the original plain text content so that it can be sent over the Web easily and faster. It compresses the content and decompresses (or extracts) that same content once you extract it. Think of the archive zip program as a plastic zip bag that you put food in it and then seal it to protect the food from spoiling.
Once you've downloaded your favorite archive zip application, you need to install it as you normally would with any other applications by following the installation instruction. It shouldn't be that hard to install the archive zip application. You can install it in any directory of your choosing and it doesn't need to be in a particular directory at all.
Just make sure that you say "yes" when it prompts (you) if you want the installation program to create an icon in the desktop for that particular archive zip application. If you said "yes," it will create an icon for that archive zip application and it will put that icon on your desktop pane. Self-explanatory!
Actually, you don't even need to have the icon shown on your desktop pane unless you need to open it to create an archive zip application to put your files in to send your files to the server. In that case, you definitely need to have an icon shown on your desktop pane.
So basically, after you'd installed your favorite archive zip on your laptop/desktop you can use it to extract your downloaded text editor that came inside the zip archive by clicking on your "raw zipped" downloaded favorite text editor.
Remember that all downloaded applications come inside an archive compression zip application -- it is totally zipped or compressed. So you need to extract/uncompress the downloaded text editor, which came inside the archive compression zip application.
Just clicking on the "raw zipped" downloaded text editor in raw format and it will open up (automatically) the archive zip application that you had installed on your computer. You see, this is why you don't need to create an icon on your computer pane because you don't need to click it to open it. It opens the archive zip application automatically every time you click on the "raw zipped" downloaded application.
Say you just downloaded a text editor called MAX's HTML Beauty++ and all you have to do is double click on that downloaded apllication and it will automatically open up your favorite zip archive application and extract your downloaded text editor for you without you having to find your zip archive application icon to double it and open it. It opens automatically for you once you double click on the downdloaded text editor.
Once it opens up the archive zip application it should show that your text editor is inside the archive zip application. In that archive zip screen, it shows a lot of options you can do, such as "create archive" for creating archive zip application packages, and "extract" option, which is to extract the (current) downloaded application. Follow the on-screen instruction and you'll be fine! It is very easy to use archive zip applications.If for some reasons you need to send files to the server, you can open the archive zip application by just clicking on the icon shown on your computer pane and it will open the archive zip application for you to use. This is why you need to allow the installation program to create an icon on your computer pane so that you can open it and use it easily.
Let's say you have some photos, or any other content for that matter, and you want to send them to a remote server, you can put those photos/content/files in an archive zip application and send them to your remote server or any server you have accessed to. And then create a link to that archive zip file name and your users will be able to download those content from your website.
Once your users downloaded the photo content they can decompress (or extract) that photo content from the archive zip application to be viewed at their own leisure.
For example, say you have a bunch of photos and you want to create an archive zip application by opening the archive zip application and then clicking on "create archive" or for some archive applications just say "create", and it will open a screen to allow you to create the archive zip application. From there, just follow the on-screen instructions and you'll be fine.
Among the instructions is that it asks for a file name for the archive zip application you're creating; for example, you can name it as "myphoto" without any extension and it will create an empty archive zip application without any content in it.
From there, you can put your photos/content inside that newly created archive zip application by copy and paste them or if the photos/content/files are on the computer pane, you can drag and drop them easily. It is very easy to create and move content into the archive zip applications.
Now you have your photos/content/files inside your newly created archive zip application with a file name for that archive zip application and ready to go. Next, you can upload the entire newly created archive zip application to your server so that your users can download them.
To allow your users to download them, you need to create a link to that particular archive zip application that you just uploaded to your server. For example, say you upload your archive zip application to your website, which has a directory called "download," you can create a link somewhere on your website page like this: <a href="http://www.mywebsite.com/download/myphoto.zip">download my photos!</a>. That is it!
Pay special attention to the extension, which in the above case, it is a ".zip" extension. So you need to specify the exact extension in order for it to work. Different archive compression applications have different extensions and they are named accordingly in a variety of extensions, i.e., .zip, .ar, .rar, .pea, etc. Check your particular archive compression applications for the extension they use.
The process just described is how you allow your users to download anything from your website -- the same sort of thing you see other websites allow their users to download some content from their websites.
Well, the first step is a little too lengthy than I would have liked but I just wanted to be very clear and precise to help you along!
Next, you'll need a local webhost to build and test your applications offline -- that is, you're using a fake web server to build and test your web applications offline on your computer without having to rent a live "real" web server. Once you've built and tested your web applications offline, you can decide to get a real web server to host your web applications online so that your website can be viewed by people all over the world.
As a matter of fact, most experienced programmers, including myself, use "fake" server to build and test applications on a daily basis. So I strongly recommend beginning programmers to do the same and use localhost to build and test your web applications. Once you finished building and testing your applications and then you can find a real web server to host your websites. Google around using phrases like this: "free webhosting services" to find a real web hosting service provider to host your websites. There are lots of them out there.
Check out my other tutorial at the bottom of this page titled: 'Migrating your website to a real live server' for a free web hosting service provider that I found on the Internet when I Googled around using phrases like this: "free web hosting services".
That free web hosting service provider that I found is one of the best free web hostings out there. I used that free web hosting to host one of my websites as well. You, too, can signup for a free web hosting account with them and use it to host your website just like I do.
Please DO NOT use free web hosting to build and test your web applications because it slows down other people using the same host. All free web hostings are shared hosting: meaning all users of the shared hosting are routed through the same bandwidth and if lots of people use their live hosting to build and test their web applications, it slows down the shared hosting traffic.
So please use your localhost to build and test your web applications.To get a "fake" web server, usually called localhost, you can search the web using a term like "localhost webserver", or you can Google a specific term like "WAMP server", "XAMPP server", "MAMP server", "VAGRANT server", or DOCKER.i.
Once you've identified which one you want, go ahead and download and then install it on your local machine, preferably on your laptop/desktop. You can choose to install it in any location on your desktop/laptop and it doesn't matter; however, for ease of use, choose the default setting shown on the installation prompts.
Once you've installed your localhost web server, you're ready to build and test your web applications just like if you had rented a real live web server from a hosting vendor. The only difference is that your "fake" web server is locally run and is not visible on the web like a real web server does. Most of the instructions on the web are self-explanatory and are very easy to follow even for beginners who never know how to program a single program. You can check out Youtube.com on tutorials on these topics as well.
Once you've installed a WAMP local host web server, all the required applications, such as the Apache (web server), MySQL (database), PHP programming language, and as well as the PHPmyAdmin (a MySQL application), are all bundled and installed completely into your local laptop/desktop to work with each other seamlessly.
In WAMP, you can work with databases using MySQL to store and retrieve data, as well as using PHP programming language to program your web applications. WAMP is not restricted to just PHP, however -- you can use other languages as well.
WAMP is a popular alternative of XAMPP for Windows. However, you can use XAMPP as well and it doesn't take much time to install XAMPP either. But developers may prefer to use WAMP since it is specifically crafted for Windows only -- unlike, XAMPP, which can be used for Linux and Mac OS as well.
However, both platforms are equally stable and provide the same functionality.
So you can choose any platform amongst the two to fulfill your objective. But all those who are searching for guidance on how to install WAMP on Windows system should follow the below-given steps. So let's get going!!
How to Install WAMP on Windows
Download the WAMP Server: Wampserver 64 bit x64
You want to choose a 64 bit version. The 32 bit is for older computers or laptops, which is outdated in today's programming world. If you're using computers that is still using a 32 bit, by all mean choose 32 bit version. To check what version your computer is running on, go to the status bar at the lower left corner of your computer screen and type in the search box: control panel and press enter.
The "Control Panel" screen should pop up. In that screen, look for a section called "System and Security" or "System and Maintenance" or anything that has a word "System" on it. For Windows 7, 8, 10, it should says "System and Security." Click on that topic and a "System and Security" screen should pop up.
Next, look for the topic "System" and click on that topic and a "System" screen should pop up. In that screen under the "System" section it lists the "System type" which should say a "64-bit Operating System or 32-bit Operating System, depending on your computer. If it says "64-bit Operating System, your computer is running on a 64-bit operating system. "32-bit Operating System", otherwise.
Initiate WAMP Server Installation Process. I'm being lazy and for the rest of the installation instructions, I will refer to an excellent instruction on the web: here it is: click here!
In that instruction, be careful in step 2. WAMP server looks for a version of Microsoft Visual C++ re-distributable package already installed on your laptop/desktop. Most of the laptops/desktops come with a Microsoft VC++ re-distributable package already pre-installed, so you don't have to do anything. However, for some odd reasons, some laptops/desktops came without that Microsoft Visual C++ re-distributable package pre-installed.
In that case, you might have to search the web for "Microsoft Visual C++ re-distributable package" and download it and install it using default settings contains in its installation application. When you install Microsoft Visual C++, it is very easy and self-explanatory, the same way you install a WAMP server -- they both are self-explanatory, allowing you to just use default settings.
FYI: If you look in the "Control Panel" screen mentioned earlier, it should shows Microsoft Visual C++ installed already; and in that case, WAMP server will find it and use it to complete the installation process, and thus, you don't need to do anything on your part, sparring you from having to search the web.
Once you get through the Microsoft Visual C++ re-distributable package installation process and proceeds to the end of the installation process, the last thing the WAMP server installation guide will prompt you to do is, to enter/choose a text editor. You can accept a default text editor in the prompt or choose your favorite text editor to use with your newly installed WAMP server. It looks something like this:

It's okay one way or another as it is not very significant if you do not choose a particular text editor or not as a default text editor for the WAMP server to use. It won't effect/harm your WAMP server at all. For beginners, I suggest that you choose the default text editor chosen by the installation.
However, I strongly recommend you just select a text editor of your choice or just leave it as a default text editor that the WAMP server chooses, which is a Microsoft notepad. In other words, by choosing a particular text editor doesn't restrict you from using other text editors with your WAMP server.
It also will prompt you to enter/choose a default web browser to use with your newly installed WAMP server. Likewise, by choosing a particular web browser doesn't restrict you from using other web browser with your WAMP server either. So it looks something like this:

Once you've finished the installation process, you can use the "fake" web server to build and test your web applications offline as you normally would with a "live" real web server. To start, click on the arrow or status icon usually on the lower right corner of your laptop/desktop screen to activate the tap that shows the "fake" web server options listing.
Note: From time to time, if you're using Windows operating system, Windows operating system usually runs updates to update its software drivers and the rest of its system files automatically and periodically. If you're using Windows OS, you may have experienced this update many times already and it's kind of annoying as well, but it's a necessary task for Windows OS, according to Microsoft.
One of the annoying things that this update causes is that it causes the WAMP server to not function properly once the update is completed.
If you experienced this and having issues with your WAMP server to not function properly, just un-install your WAMP server completely from your system and then re-install it again and it should work properly.
Yes, it is very annoying having to un-install and re-install your WAMP server every time a Windows operating system runs its update.
Make sure that you move all of your "projects" in the "www" directory to a different location (or directory) before un-installing your WAMP server; because if you don't, it will delete all of your projects in the "www" directory.
Let's continue on:
It should show an icon that looks something like below with a status icon that usually appears on the lower right corner of your laptop/desktop screen, but with a particular color on it. A green color (as shown below) signifies as the wampserver is ready to use; a grey or pink color, it is not activated; a yellow, it is partially ready and in the process of being ready as it is finishing the loading process.
So in essence, every time you start/load or turn on your wampserver, it goes through a series of steps to initialize the wampserver, showing the colors of its readiness from grey to pink to yellow to green. Green means the wampserver is ready for usage.

If it is inactive, all you have to do to fire up your wampserver is to double click on the default icon on your laptop pane that looks something like below:

Usually, when you turn off your laptop, WAMP server is also turned off and no longer active and the green status icon you see above is not shown. When it is turned off, the status icon that usually appears on the lower right corner of your laptop/desktop screen doesn't show the WAMP server icon because it is not activated.
To activate it or turn on your WAMP server, double click on the default icon on your laptop pane to get it activated.
Once your "fake" server is up and running, you can do pretty much just about anything you do with a "live" server. You can click on the arrow next to the green status icon to reveal other options, such as a PHP icon to see what version of PHP is installed on your "fake" server; as well as clicking on PHPmyAdmin to work with database.
Note that PHPmyAdmin in your "fake" server doesn't require you to enter a password, although you can if you want -- but why bother to complicate yourself in having to enter a password every time you try to access your PHPmyAdmin? So just enter 'root' for the username and don't enter a password on the password field. Leave it blank as it is!
Just click "Go" without entering a password and it will open the PHPmyAdmin panel for you.
In the PHPmyAdmin, you can create databases and tables and do pretty much just about anything about database programming.
As stated above, when a localhost is up and running the status icon usually appears on the lower right corner of your laptop/desktop screen. Click on the arrow to reveal the the localhost options. In this option window, you can find a lot of options to choose from, such as PHPmyAdmin, just to name one.
You can click on the particular option to work with it. For example, among the options there is a "localhost" option. Click on that "localhost" option and it will open up a screen that looks something like the following:

As you can see, it shows the configuration status of the localhost such as what version of various entities: Apache, PHP, MySQL, etc. Most of them are really not useful for beginners. Experienced programmers can make use some of these configurations.
The diagram above combines with the one listed below is what it should looks like inside a real server. This localhost web server mimmicks what a real server looks like but on an offline mode.
The localhost also contains a section in the lower half that lists content that is more relevant to beginning users of Wampserver, such as tools and your actual projects that you had created. For example, below it lists three projects that I've created: advanced, framework, noon2noon.com:

If you click on one of the projects it will execute/load the project. For example, if I click on the project called noon2noon.com it will load and display my website called noon2noon.com.
However, you can load your website on the browser's url bar as well, the same way you normally would with your regular "live" server. That is the typical usage of localhost: you don't need to load your website through localhost option window, but instead, through a normal loading process in the browser's url bar.
You should try to create a very simple website and click on it in the project section to see what it looks like on your "fake" server. When you create your projects, place them in a directory where you installed your Wampserver. For example, in my case, I installed my Wampserver in a directory that looks like the following:

As you can see, my root directory is called "Desktop" followed by a directory that I named it as "wamp64" followed by a directory called "www." This directory called "www" is created automatically by the installation, so you really don't have to create it yourself. The only directory that you need to create and specify during the Wampserver installation is the "wamp64" part or whatever name you choose. I chose to name it "wamp64."
Any projects you build have to be placed inside the "www" directory in order to be visible by your localhost. For example, in my case, I placed my projects in that "www" directory and inside my project noon2noon.com it contains content that looks like the following:

One particular content worths mentioning is the index.php file. This is the main starting script file that the server/localhost calls first thing when you try to load the website by typing in your url bar like http://www.noon2noon.com. However, that is for your real live web server when you migrate your website to a real web server.
But for this tutorial, you're using a fake server called localhost; and therefore, you have to type in the browser bar using localhost instead of www.
So you can simply replace the domain specification 'www' with 'localhost' and just type the name of the folder following it as, in my case, http://localhost/noon2noon.com or simply just localhost/noon2noon.com and it will load the website automatically.
For my project advanced, which its inside content looks similar to my other two projects framework and noon2noon.com, I can just do the same like this http://localhost/advanced, and likewise for the other one http://localhost/framework, and both websites will load automatically.
Notice that you can include an index.php or index.html file as well since it doesn't require you to specify an extension of either a .php or a .html and it will work just fine. For examples: http://localhost/noon2noon.com/index, http://localhost/advanced/index, http://localhost/framework/index, and all websites will load automatically.
Please note that when you migrate your websites to a real web server, you have to abide by your web hosting's rule, which tells you what kind of an extension of either a .php or an .html that their server is using. If they're using a .php extension, you'll have to rename your index file with that extension. Likewise, if they're using an .html extension, you'll have to rename your index file extension as such.
For a localhost, it doesn't matter. It will read from either .php extension or .html file extension.
For starter, in your case, just create an index.php or index.html file and throw it in a folder and place that folder inside the "www" directory and type http://localhost/ follows by your folder name in the url browser bar to see your website comes alive. Try it!
If your website doesn't come alive and showing a weird screen that looks like the following, it means that for some reason the localhost cannot read your index file. Or it means that the route in the url bar that you typed is incorrect. The localhost can't find the file contains in the route that you typed in the url bar:

As you can see, there is no index file listed in the main folder. I deleted it on purpose and the localhost can't find the file contains in the route that I typed in the url bar.
Localhost server is very vague in their error messaging system and that's a source of frustation for a lot of new programmers.
Remember that each website has to have only one index file as a main starting application file. So make sure that you have a functional index file and it has to be only one index file. No index.php and index.html at the same location vying as the main starting application file.
Once you are finished building and testing, you can migrate your projects to your live real web hosting server. For example, in my case, I just take the folder containing the particular project, i.e., noon2noon.com folder, and upload the entire folder to my real live server. That's how you get started in developing website applications.
For starter, you can create a folder and name it and then create an index.php or index.html file as well as other files/folders and put them inside that folder that you just created which contains other files/folders as well and upload the entire folder using FileZilla. See my other tutorial on how to use FileZilla.
That is it! Very simple to have your own "fake" server. And from here, the possiblities are endless! Have fun programming!
For beginners, building a website is a daunting task, even for very simple websites that don't have ordinary bells and whistles and are still very challenging to say the least. Fortunately, the folks at the W3Schools.com provide all sort of examples and ready-made web site templates to help beginners get started.
Let's take a look at one template and illustrate how you (beginners) can build your own web site using the ready-made template and customize it to suite your taste.
First go to https://www.w3schools.com/w3css/w3css_downloads.asp and download the css definition (or file) and place it in a folder called css. The default file name is w3.css. You can rename the css file if you like, say css.css or style.css. If you do, don't forget to change the css file name accordingly in your index.php file at the css area at the top of the index.php file to reflect the change in the css file name.
Next, in the same page where you're downloading the css, look on the left side under the category name Examples and try to find a topic name called W3.CSS Templates. Or you can go to https://www.w3schools.com/w3css/w3css_templates.asp
You can scroll down to see the various templates available to use. Pick one and go from there!
If the templates mentioned in the above link is not enough for your tastes, you can find more templates to use right here!
Once you decided which one you want to use, go ahead and click on the "Try it Yourself" button to see the actual code.
Next, copy the actual code, character by character, without missing any character. In other words, no typos in your part or else your web site won't look as intended. If your web site doesn't look like it is intended, try to go back and see if you had any typos in your copied code.
The folks at W3Schools.com used some sort of techniques, such as disabling the "hot link" ability, to disable the copy and paste ability from the web browser. So you can't actually use your web browser to copy and paste the code shown in the templates. You'll have to use advanced editors or tools to copy and paste the code in the templates.
For beginners, advanced tools are out of reach, so just try to copy it manually by hand character by character until you completely copied everything in the template. Yes, it is a pain, but that is what you have to do to learn. Name that template as either index.php or index.html. This is your main index file -- or your main web site file.
Once you have the css file downloaded as well as the template copied and name it as either index.php or index.html, then you need to create a main folder as well as a css folder.
Next, create another folder called image and put all the images/photos that you want to use in your website in that image folder.
You can name them whatever names you like for any folders you create, i.e., MyWebsite, MyFirstProject (for the main folder), css, style (for the css folder), image (for the image folder), etc.
You need to put the index.php or index.html as well as the css folder and the image folder in the main folder. The css file containing the css definitions should be inside the css folder, while the image folder contains all images you need to use. Self-explanatory!.
So your main folder contains everything you need. So you need to put everything in this main folder, including other folders as well such as css, image, etc. The index file should be among the css and image folders as peers at the same level.
That's all you need for this simple website. Three folders: main folder (i.e., MyWebsite or MyFirstProject, or whatever), css folder, and image folder. Plus the index.php/index.html and all three are peers -- meaning they are at the same level in directory. For example:

Of course, you can have more folders and other contents as well as your website gets sophisticated, but for this simple website the three items are all you need for now.
As you can see, I put my main folder called MyWebSite inside the www localhost folder for building and testing web applications. The index.php file contains the content listed below and the actual rendering page content is shown in the following.
Let's see one particular template called "Social Media Template" taken from W3Schools.com website in the W3.CSS Templates category, but I customized it slightly. Here it is:

Here is the actual code along with the commented out code that contained in the original template shown in the W3Schools.com:
File: index.php
<!-- all HTML document start with a !doctype -->
<!-- it is a Document Type declaration to tell the web browser of -->
<!-- what version of the HTML markup language in which a web page -->
<!-- is written. -->
<!-- every time a browser reads a document such as an HTML document it -->
<!-- needs to know what version the HTML markup language is written in -->
<!-- so that it can parse it correctly. -->
<!DOCTYPE html>
<html>
<head>
<title>Template</title>
<!-- a meta (<meta>) tag provides metadata information about -->
<!-- the HTML document. -->
<!-- a metadata information will not be displayed on the page, -->
<!-- but will be machine/browser parsable. -->
<!-- metadata elements are typically used to specify page description, -->
<!-- keywords, author of the document, last modified, and other metadata. -->
<!-- you put metadata in <meta> tags-->
<!-- meta (<meta>) tags are documents for the browsers to read and -->
<!-- used the meta content, for example, you can specify a view port -->
<!-- device dimension such as width. -->
<!-- the word "meta" means self or itself, referring to itself or -->
<!-- a self-referential. -->
<!-- so a self-referential. -->
<!-- meta tags can contain attributes, i.e., name and content. -->
<!-- the two most frequently used in a meta tag are name and content -->
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- the following link is the css link stored in folder named css -->
<link rel="stylesheet" href="./css/mobile.css">
<!-- the following two links were broken down to fit the screen display -->
<!-- these two links are specialized css stored in cloudflare.com -->
<!-- you only need to incude these links if you use awesome fonds and -->
<!-- bootsrap code like form input boxes, textarea, and dialog boxes -->
<!-- you can check out bootstrap tutorials on W3Schools as well! -->
<link rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.6.3/
css/font-awesome.min.css">
<link rel="stylesheet"
href="http://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/
3.2.0/css/bootstrap.min.css">
<!-- the following three lines link to jquery, bootstrap, and -->
<!-- my own Javascript files -->
<script src="https://code.jquery.com/w3/1.4.5/jquery.w3-1.4.5.min.js">
</script>
<script type="text/javascript" src="js/bootstrap.min.js"></script>
<script type="text/javascript" src="javascript/javascript.js"></script>
</head>
<!-- this is the start of the web site body -->
<!-- the 'class' attribute specifies the css that this body uses to -->
<!-- beautify itself -->
<!-- disregard the theme class, but make use of the color class -->
<!-- this is where you set your body background color, light grey, in this -->
<!-- case! -->
<!-- check out the list of pre-made colors at the bottom of this listing -->
<!-- in this body is where you also set your text size using w3-tiny -->
<!-- w3-small, w3-medium, w3-large, w3-xlarge, w3-xxlarge, -->
<!-- w3-xxxlarge, w3-jumbo -->
<!-- as you use W3Schools templates, you can put multiple css classes in an
element, i.e., <body>, <div>, <span>, <p>, <a>, <button>, <img>, etc. -->
<body class="w3-theme-l5 w3-light-grey">
<!-- some of the following codes were broken down into multiple lines -->
<!-- to fit the screen display -->
<!-- Navbar -->
<!-- this is the div that wraps around the navbar -->
<div class="w3-top">
<!-- in the navbar you can style the look-and-feel using css classes. -->
<!-- for example, you can make the navbar thicker or thiner by specifying -->
<!-- the class as w3-padding-tiny, w3-padding-small, -->
<!-- w3-padding-large, etc. -->
<!-- in the example site illustrated above I style the navbar as w3-blue! -->
<div class="w3-bar w3-theme-d2 w3-left-align w3-small w3-blue">
<a class="w3-bar-item w3-button w3-hide-medium w3-hide-large w3-right
w3-padding-small w3-hover-white w3-small w3-theme-d2"
href="javascript:void(0);" onclick="openNav()">
<i class="fa fa-bars"></i></a>
<!-- notice that the anchor tags contain "#" used in place ---->
<!-- of the actual url that you need to provide! ---->
<!-- the "#" is just a placeholder for the real url! ---->
<!-- so don't forget to replace "#" with the actual url! ---->
<!-- for example: "http://www.example.com/homefolder/myfile.php" ---->
<a href="#" class="w3-bar-item w3-button w3-padding-large w3-theme-d4">
<i class="fa fa-home w3-margin-right"></i>Logo</a>
<a href="#" class="w3-bar-item w3-button w3-hide-small w3-padding-large
w3-hover-white" title="News"><i class="fa fa-globe"></i></a>
<a href="#" class="w3-bar-item w3-button w3-hide-small w3-padding-large
w3-hover-white" title="Account Settings"><i class="fa fa-user"></i></a>
<a href="#" class="w3-bar-item w3-button w3-hide-small w3-padding-large
w3-hover-white" title="Messages"><i class="fa fa-envelope"></i>
<div class="w3-dropdown-hover w3-hide-small">
<button class="w3-button w3-padding-large" title="Notifications">
<i class="fa fa-bell"></i>
<span class="w3-badge w3-right w3-small w3-green">3</span>
</button>
<!-- here is again the use of "#" as a placeholder for the real url! ---->
<div class="w3-dropdown-content w3-card-4 w3-bar-block"
style="width:300px">
<a href="#" class="w3-bar-item w3-button">One new friend request</a>
<a href="#" class="w3-bar-item w3-button">John Doe posted on
your wall</a>
<a href="#" class="w3-bar-item w3-button">Jane likes your post</a>
</div>
</div>
<a href="#" class="w3-bar-item w3-button w3-hide-small w3-right
w3-padding-medium w3-hover-white" title="My Account">
<img src="./image/paul_tuon.jpg" class="w3-circle"
style="height:23px;width:23px" alt="Avatar"> </a>
</div>
</div> <!-- end div class="w3-top" -->
<!-- the following code block is the code that gets used instead of the -->
<!-- above navbar when a mobile device is used to load -->
<!-- this web site -->
<!-- Navbar on small screens -->
<!-- here is again the use of "#" as a placeholder for the real url! ---->
<div id="navDemo" class="w3-bar-block w3-theme-d2 w3-hide
w3-hide-large w3-hide-medium w3-large">
<a href="#" class="w3-bar-item w3-button w3-padding-large">Link 1</a>
<a href="#" class="w3-bar-item w3-button w3-padding-large">Link 2</a>
<a href="#" class="w3-bar-item w3-button w3-padding-large">Link 3</a>
<a href="#" class="w3-bar-item w3-button w3-padding-large">My Profile</a>
</div>
<!-- now the navbar code is done! -->
<!-- at this point there are 0 open <div> tag -->
<!-- Page Container -->
<!-- remember that there are typically four sections in a web site: -->
<!-- the head section, the navbar section, the main body content, -->
<!-- and the footer -->
<!-- so the following is the start of the main content of the web site, -->
<!-- and this section is the biggest section. -->
<!-- this main container has a maximum width of 1400 pixels -->
<!-- and spaces between the navbar and the start of the main -->
<!-- container or content is 80 pixels. -->
<!-- take a look at the gap in the web site above for a visual guide! -->
<!-- for a better practice is to use percentage as in 100% -->
<!-- of the screen width rather than specifying the exact width! -->
<!-- that way it works much better on different screen sizes! -->
<!-- pay special attention to one class: w3-container -->
<!-- 'container' is sort of a basket to hold something, in this case, -->
<!-- it holds a grid of column layout -->
<!-- in a later case, it holds a (small) profile container area! -->
<!-- as you can see, class w3-container can be used inside -->
<!-- another container area as well -->
<!-- in this case, this w3-container class acts as the main content -->
<!-- holder, holding everything in the body of the entire page! -->
<!-- remember that the whole website has four sections: navbar section, -->
<!-- head section, the main body section, and the footer section! -->
<!-- so this div has a w3-container class to hold the entire content -->
<!-- and this entire content is actually the 3-column layout grid! -->
<div class="w3-container w3-content" style="max-width:1400px; margin-top:80px">
<!-- The Grid -->
<!-- W3Schools provides grid system for us to use! -->
<!-- for a complete in depth tutorial see W3Schools on this topic! -->
<!-- pay special attention to a class called w3-row -->
<!-- so two classes that are central to W3Schools framework are -->
<!-- w3-container and w3-row -->
<!-- you'll make use of these two classes very often! -->
<!-- basically, the grid must be inside the container: w3-container! -->
<!-- and the container, w3-container, can contain rows of content! -->
<!-- this grid starts with a class w3-row -->
<!-- this is sort of the anchor div to hold the entire grid or one row! -->
<!-- class w3-row is a grid system. think of w3-row as a table row where -->
<!-- you can arrange grid data content in it. so if you have data content -->
<!-- that are normally arranged in rows in a table, you can use this -->
<!-- w3-row to hold those data content in table rows-like display! -->
<!-- however, in this website we have only one row of a table row! -->
<!-- if we have more data content that needs another table row, all we -->
<!-- have to do is create another div containing this w3-row class and -->
<!-- put it after the closing of this div shown below! -->
<!-- see the closing of this div later! -->
<!-- if you look at the website illustrated above, you'll see the -->
<!-- whole content body is inside a div that contains the class w3-row. -->
<!-- this is one row of content containing a three-column layout. -->
<!-- after the closing of this div w3-row, you can create more rows -->
<!-- of content by creating more divs that contain the class w3-row. -->
<!-- for each div that contains w3-row you can format your grid layout -->
<!-- any way you like, say, a four-column layout or whatever layout -->
<!-- configuration you desire! -->
<!-- here is the row! -->
<div class="w3-row">
<!-- here is inside the row! -->
<!-- now inside the anchor div or more specifically, -->
<!-- the w3-row (or grid) there are columns layout: a one-column -->
<!-- display, a two-column display, a three-column display, etc. -->
<!-- in this case, we have a three-column layout web site! -->
<!-- Left Column -->
<!-- this is the left column in the web site: see profile area column! -->
<!-- m3 is short for medium 3 out of 12 columns: 3-twelfth of the grid -->
<!-- W3Schools uses three sizes: small (s), medium (m), large (l) -->
<!-- so if you see s1 means a small scale grid with one-twelfth of -->
<!-- the grid. m7 is a medium scale layout with 7/12 of the total -->
<!-- grid layout. -->
<!-- likewise, an l2 (that is "L" and 2) means 1arge scale layout-->
<!-- with a two-twelfth of the total grid layout! -->
<!-- here, we have a medium scale with 3/12th of the total grid layout -->
<!-- as you can see, this left column has a class w3-container to hold -->
<!-- the entire left side area! -->
<!-- as stated above, class w3-container can be used inside this -->
<!-- container area as well! sort of containers within container! -->
<div class="w3-col m3 w3-container">
<!-- Profile -->
<!-- w3-card is a class to make the profile looks like a deck -->
<!-- of cards, w3-round will make the deck of cards rounded -->
<!-- edges on all 4 corners -->
<div class="w3-card w3-round w3-light-blue">
<!-- here is where class w3-container gets used to hold-->
<!-- a profile area -->
<div class="w3-container">
<h4 class="w3-center">My Profile</h4>
<p class="w3-center"><img src="./image/paul_tuon.jpg"
class="w3-circle" style="height:106px;width:106px"
alt="A Profile Picture"></p>
<hr>
<p><i class="fa fa-pencil fa-fw w3-margin-right
w3-text-theme"></i> Designer, UI</p>
<p><i class="fa fa-home fa-fw w3-margin-right
w3-text-theme"></i> Minneapolis, MN (US)</p>
<p><i class="fa fa-birthday-cake fa-fw w3-margin-right
w3-text-theme"></i> April 1, 2020</p>
</div>
</div>
<br>
<!-- Accordion -->
<!-- this block of code contains an accordion-like feature -->
<!-- when a user clicks on an item it slides down to reveal the content! -->
<!-- class w3-card is a css that made to look like a deck of cards -->
<div class="w3-card w3-round">
<div class="w3-pale-blue">
<!-- when a user clicks on "My Groups" it calls myFunction() -->
<!-- and it displays an accordion style revealing the content -->
<!-- you might want to experiment using other elements such -->
<!-- as div or span or other elements instead of button! -->
<button onclick="myFunction('Demo1')" class="w3-button
w3-block w3-theme-l1 w3-left-align">
<i class="fa fa-circle-onotch fa-fw w3-margin-right">
My Groups</i></button>
<!-- here is again w3-container gets used! -->
<!-- note that w3-hide hides the content inside the -->
<!-- div when the page is loaded! -->
<!-- it will only reveal the content when a user clicks -->
<!-- on "My Groups"! -->
<div id="Demo1" class="w3-hide w3-container">
<p>Some text..</p>
</div>
<!-- when a user clicks on "My Events" it calls myFunction() -->
<!-- and it displays an accordion style calendar of events -->
<!-- by sliding down to reveal the content -->
<!-- you might want to experiment using other elements such -->
<!-- as div or span or other elements instead of button! -->
<!-- right here where you might want to place a break: "<br>" -->
<!-- to make the gap between the two accordion item elements! -->
<!-- so instead of using "<br>" you might want to use -->
<!-- css styling to specify how much gap you want because -->
<!-- "<br>" might be bigger/smaller gap than you like! -->
<!-- so using css to style the gap is probably a good idea! -->
<button onclick="myFunction('Demo2')" class="w3-button w3-block
w3-theme-l1 w3-left-align"><i class="fa fa-calendar-check-0
fa-fw w3-margin-right"> My Events</i></button>
<!-- here is again w3-container gets used! -->
<!-- again w3-hide hides the content inside the -->
<!-- div when the page is loaded! -->
<!-- it will only reveal the content when a user clicks -->
<!-- on "My Events"! -->
<div id="Demo2" class="w3-hide w3-container">
<p>Some other text..</p>
</div>
<!-- likewise, when a user clicks on "My Photos" it calls -->
<!-- myFunction() and it displays an accordion style album -->
<!-- of photos by sliding down to reveal the photos in a -->
<!-- two-column layout -->
<!-- if you provide photos in the below container: a photo -->
<!-- album container, it will display them when a user -->
<!-- clicks on "My Photos" -->
<!-- you might want to experiment using other elements such -->
<!-- as div or span or other elements instead of button! -->
<!-- right here where you might want to place a break: "<br>" -->
<!-- to make the gap between the two accordion item elements! -->
<!-- so instead of using "<br>" you might want to use -->
<!-- css styling to specify how much gap you want because -->
<!-- "<br>" might be bigger/smaller gap than you like! -->
<!-- so using css to style the gap is probably a good idea! -->
<button onclick="myFunction('Demo3')" class="w3-button
w3-block w3-theme-l1 w3-left-align">
<i class="fa fa-user fa-fw w3-margin-right"> My Photos
</i></button>
<!-- class w3-container is used to hold the photos album layout -->
<!-- w3-hide is a class to hide the element: diplay: none -->
<!-- as you can see, when the web site is loaded, "Demo3" is -->
<!-- not shown! -->
<!-- it will only be shown when a user clicks on -->
<!-- "My Photos" button! -->
<div id="Demo3" class="w3-hide w3-container">
<div class="w3-row-padding">
<br>
<!-- the following is where you put your photo album! -->
<!-- class w3-half is a grid layout as a two-column -->
<!-- layout relative to the class w3-container used -->
<!-- in the album layout so the photos are arranged -->
<!-- side by side as a two-column layout -->
<!-- inside the div or img tags you can embedd inline css to style your layout: width, height, etc. -->
<!-- for example: <div class="w3-half" style="width: 100px; height: 50px"> ... </div> -->
<div class="w3-half">
<img src="./image/paul_tuon.jpg" style="width: 100%; height: 50%"
class="w3-margin-bottom">
</div>
<div class="w3-half" style="width: 200px; height: 150px">
<img src="./image/graduation.jpg"
class="w3-margin-bottom">
</div>
<!-- this is another two-column grid stacking below the above photos -->
<div class="w3-half">
<img src="./image/paul_tuon.jpg" style="width: 100%"
class="w3-margin-bottom">
</div>
<div class="w3-half">
<img src="./image/graduation.jpg" style="width: 100%"
class="w3-margin-bottom">
</div>
<!-- this is another two-column grid stacking below the above photos -->
<div class="w3-half">
<img src="image/example5.jpg" style="width: 100%"
class="w3-margin-bottom">
</div>
<div class="w3-half">
<img src="image/graduation.jpg" style="width: 100%"
class="w3-margin-bottom">
</div>
</div> <!-- end div class="w3-row-padding" -->
</div> <!-- end div id="Demo3" -->
</div> <!-- end div class="w3-white" -->
</div> <!-- end div class="w3-card w3-round" -->
<!-- this is the end of an accordion-like feature! -->
<!-- at this point there are still 3 open div -->
<!-- Interest: the miscellaneous content of interest! -->
<!-- w3-hide-small is to not display the content when mobile -->
<!-- device is used to load the web site! so "Interests" content -->
<!-- won't be loaded if mobile device is being used to load -->
<!-- this web site -->
<div class="w3-card w3-round w3-teal w3-hide-small">
<div class="w3-container">
<p>Interests</p>
<p>
<span class="w3-tag w3-small w3-theme-d5">News</span>
<span class="w3-tag w3-small w3-theme-d4">W3Schools</span>
<span class="w3-tag w3-small w3-theme-d3">Labels</span>
<span class="w3-tag w3-small w3-theme-d2">Games</span>
<span class="w3-tag w3-small w3-theme-d1">Friends</span>
<span class="w3-tag w3-small w3-theme">Games</span>
<span class="w3-tag w3-small w3-theme-l1">Friends</span>
<span class="w3-tag w3-small w3-theme-l2">Food</span>
<span class="w3-tag w3-small w3-theme-l3">Design</span>
<span class="w3-tag w3-small w3-theme-l4">Art</span>
<span class="w3-tag w3-small w3-theme-l5">Photos</span>
</p>
</div>
</div>
The following block of code contained in the original template
<!-- Alert box -->
<!-- when a user clicks on this div area an alert box pops up -->
<!--
<div class="w3-container w3-display-container w3-round w3-theme-14
w3-border w3-theme-border w3-margin-bottom w3-hide-small w3-red">
<span onclick="this.parentElement.style.display='none'"
class="w3-button w3-theme-13 w3-display-topright">
<i class="fa fa-remove"></i>
</span>
<p><strong>Hey,</strong></p>
<p>People are looking at your profile. Find out who!</p>
</div>
-->
</div> <!-- end left column -->
<!-- at this point there are still 2 open <div> tags -->
<!-- start middle column -->
<!-- this is the start of the middle column. -->
<!-- size m7 means 7/12 of the grid -->
<!-- as you can figure it out: there are 12 columns in the entire grid -->
<!-- if the left side column is m3, meaning 3/12 of the grid, -->
<!-- and middle column is 7/12 of the grid, -->
<!-- the right column has to be 2/12 of the grid! -->
<div class="w3-col m7">
<!-- right here where I add some new content to the middle column -->
<!-- I add a scrolling message board to make it more flashy. for example: -->
<div class="w3-row-padding">
<!-- notice that you need to use the entire length of the grid: m12 -->
<!-- meaning the entire middle column -->
<div class="w3-col m12">
<div class="w3-card-2 w3-round w3-white">
<div class="w3-container w3-padding">
<marquee bgcolor=white width="100%" height="50">
<font size="5" color="#FF66FF">
Welcome to the 21st century and beyond where digital mobile rules!</font>
<font size="5" color="#1883FF">More content to scroll!</font>
</marquee>
</div>
</div>
</div>
</div>
<div class="w3-row-padding">
<div class="w3-col m12">
<div class="w3-card w3-round w3-white">
<div class="w3-container w3-padding">
<h6 class="w3-opacity">Social Media Template</h6>
<p contenteditable="true" class="w3-border
w3-padding">Status: Feeling blue!</p>
<button type="button" class="w3-button w3-theme">
<i class="fa fa-pencil"></i> Post
</button>
</div>
</div>
</div>
</div>
<div class="w3-container w3-card w3-round w3-blue w3-margin">
<img src="./image/paul_tuon.jpg" alt="Avatar" class="w3-left
w3-circle w3-margin-right" style="width:60px">
<span class="w3-right w3-opacity">1 min</span>
<h4>John Doe</h4>
<hr class="w3-clear">
<p>This is just an ordinary content! You can put whatever
content you want!</p>
<div class="w3-row-padding" style="margin:0 -16px">
<!--
<div class="w3-half">
<img src="./image/graduation.jpg" alt="just a picturer"
style="width: 100%" class="w3-margin-bottom">
</div>
<div class="w3-half">
<img src="./image/paul_tuon.jpg" alt="another picture"
style="width: 100%" class="w3-margin-bottom">
</div>
-->
</div>
<button type="button" class="w3-button w3-theme-d1 w3-margin-bottom">
<i class="fa fa-thumbs-up"></i> Like</button>
<button type="button" class="w3-button w3-theme-d2 w3-margin-bottom">
<i class="fa fa-comment"></i> Comment</button>
</div>
<div class="w3-container w3-card w3-round w3-khaki w3-margin"><br>
<!--
<img src="./image/graduation.jpg" alt="Avatar" class="w3-left
w3-circle w3-margin-right" style="width:60px">
-->
<span class="w3-right w3-opacity">16 min</span>
<h4>Jane Doe</h4>
<hr class="w3-clear">
<p>Lorem ipsum dolor. Lorem ipsum dolor. Lorem ipsum dolor.
Lorem ipsum dolor. Lorem ipsum dolor.</p>
<button type="button" class="w3-button w3-theme-d1 w3-margin-bottom">
<i class="fa fa-thumbs-up"></i> Like</button>
<button type="button" class="w3-button w3-theme-d2 w3-margin-bottom">
<i class="fa fa-comment"></i> Comment</button>
</div>
The following block of code contained in the original template
<!--
<div class="w3-container w3-card w3-round w3-lime w3-margin"><br>
<img src="./image/paul_tuon.jpg" alt="Avatar" class="w3-left
w3-circle w3-margin-right" style="width:60px">
<span class="w3-right w3-opacity">30 min</span>
<h4>Angie Jane
<hr class="w3-clear">
<img src="./image/gradution.jpg" class="w3-margin-bottom"
style="width:100%">
<p>Lorem ipsum dolor. Lorem ipsum dolor. Lorem ipsum dolor.
Lorem ipsum dolor. Lorem ipsum dolor.</p>
<button type="button" class="w3-button w3-theme-d1 w3-margin-bottom">
<i class="fa fa-thumbs-up"></i> Like</button>
<button type="button" class="w3-button w3-theme-d2 w3-margin-bottom">
<i class="fa fa-comment"></i> Comment</button>
</div>
-->
<!-- on the left side column there is an accordion slide down/up -->
<!-- feature which contains three sections: My Groups, My Events, -->
<!-- My Photos! you can use that code example to place your -->
<!-- accordion feature anywhere on the website! -->
<!-- let's put that same accordion feature in the middle column at -->
<!-- the very bottom just before the start of the footer! -->
<!-- just remember that each accordion item must contains -->
<!-- a unique id, e.g., group, event, photo! -->
<!-- start accordion style feature! -->
<!-- Accordion -->
<div class="mobile-card mobile-round">
<div class="mobile-pale-blue">
<!-- when a user clicks on "My Groups" it will call -->
<!-- myFunction() and it displays an accordion -->
<!-- style revealing the content -->
<!-- you might want to experiment using other elements such -->
<!-- as div or span or other elements instead of button! -->
<button onclick="myFunction('group')"
class="mobile-button mobile-block mobile-theme-l1
mobile-left-align">
<i class="fa fa-circle-onotch fa-fw
mobile-margin-right"> My Groups</i>
</button>
<div id="group" class="mobile-hide mobile-container">
<p>Some text..</p>
</div>
<!-- when a user clicks on "My Events" it will call -->
<!-- myFunction() and it displays an accordion -->
<!-- style calendar of events by sliding down to -->
<!-- reveal the content! -->
<!-- you might want to experiment using other elements such -->
<!-- as div or span or other elements instead of button! -->
<button onclick="accordion('event')"
class="mobile-button mobile-block mobile-theme-l1
mobile-left-align">
<i class="fa fa-calendar-check-0 fa-fw
mobile-margin-right"> My Events</i>
</button>
<div id="event" class="mobile-hide mobile-container">
<p>Some other text..</p>
<div>
<!-- likewise, when a user clicks on "My Photos" it calls -->
<!-- myFunction() and it displays an accordion style -->
<!-- album of photos by sliding down to reveal the photos -->
<!-- in a two-column layout -->
<!-- if you provide photos in the below container: a photo -->
<!-- album container! it will display them when a user -->
<!-- clicks on "My Photos" -->
<!-- the below layout is a two-column layout displaying -->
<!-- two photos side by side! -->
<!-- in this example, there are six photos displaying -->
<!-- in pairs to make it three rows! -->
<!-- you might want to experiment using other elements such -->
<!-- as div or span or other elements instead of button! -->
<span class="hljs-string"><button onclick="accordion('photo')"
class="mobile-button mobile-block mobile-theme-l1
mobile-left-align"><i class="fa fa-user
fa-fw mobile-margin-right"> My Photos</i>
</button>
<div id="photo" class="mobile-hide mobile-container">
<div class="mobile-row-padding">
<br>
<div class="mobile-half">
<img src="./image/paul_tuon.jpg" style="width: 100%"
class="mobile-margin-bottom">
</div>
<div class="mobile-half">
<img src="./image/paul_tuon_graduation.jpg"
style="width: 100%" class="mobile-margin-bottom">
</div>
<div class="mobile-half">
<img src="./image/paul_tuon.jpg"
style="width: 100%" class="mobile-margin-bottom">
</div>
<div class="mobile-half">
<img src="./image/paul_tuon_graduation.jpg"
style="width: 100%" class="mobile-margin-bottom">
</div>
<div class="mobile-half">
<img src="image/paul_tuon.jpg"
style="width: 100%" class="mobile-margin-bottom">
</div>
<div class="mobile-half">
<img src="image/paul_tuon_graduation.jpg"
style="width: 100%" class="mobile-margin-bottom">
</div>
</div> <!-- end div class="mobile-row-padding" -->
</div> <!-- end div id="photo" -->
</div> <!-- end div class="mobile-pale-blue" -->
</div> <!-- end div class="mobile-card mobile-round" -->
<!-- end accordion style feature! -->
</div> <!-- end middle column -->
<!-- start right column -->
<!-- here it is: right column is 2/12 of the grid -->
<div class="w3-col m2">
<div class="w3-card w3-round w3-aqua w3-center">
<div class="w3-container">
<p>Upcoming Events:</p>
<img src="./image/image_105.jpg" class="w3-margin-bottom"
style="width:100%">
<p><strong>Holiday</strong></p>
<p>Friday 15:00</p>
<p><button type="button" class="w3-button w3-theme-14
w3-block">Info</button></p>
</div>
</div>
<div class="w3-card w3-round w3-pink w3-center">
<iv class="w3-container">
<p>Friend Request</p>
<!--
<img src="./image/graduation.jpg" class="w3-margin-bottom"
style="width:50%">
-->
<span>Jane Doe</span>
<div class="w3-row w3-opacity">
<div class="w3-half">
<button type="button" class="w3-button w3-block-14
w3-green w3-section" title="Accept">
<i class="fa fa-check"></i></button>
</div>
<div class="w3-half">
<button type="button" class="w3-button w3-block-14
w3-red w3-section" title="Decline">
<i class="fa fa-remove"></i></button>
</div>
</div>
</div>
</div>
<br>
<div class="w3-card w3-round w3-purple w3-padding w3-center">
<p>ADS</p>
</div>
<br>
</div> <!-- end right column -->
<!-- here is the closing div for class w3-row! -->
</div> <!-- end grid containing class w3-row -->
<!-- right here, if you have more table rows-like data content, -->
<!-- you can add another div containing a class w3-row -->
<!-- after all the data content for this particular row has been -->
<!-- included, you can close out this div containing class w3-row -->
<!-- you can keep repeating this pattern over and over as you -->
<!-- need to make your website looks like table rows-like content! -->
<!-- the rows have to be inside the closing of the div that -->
<!-- contains w3-container. -->
<!-- as you may remember that the two most important classes in the W3 framework -->
<!-- css are w3-container and w3-row. -->
<!-- this means that you can nest these two classes inside one another in many -->
<!-- levels deep inside one another to make your grid as small or big as you want! -->
<!-- just remember that class w3-row has to be inside class w3-container! -->
<!-- and inside this class w3-row it can contain class w3-container as well to -->
<!-- nest your container inside a row! sort of a row of table that contains a container! -->
<!-- now inside this class w3-container can also contains nested rows -- I mean many 'rows' -->
<!-- of content (or container, more specifically, w3-container classes) -->
<!-- you can keep repeating this pattern over and over as you -->
<!-- need to make your grid looks like table rows-like content! -->
<!-- this means that you can grid your grids to line up very close or far apart from each other! -->
<!-- you can grid your grids to place your content anywhere in the website to position your -->
<!-- content to suite the look and feel like a drag and drop items arrangement in a desktop pane! -->
<!-- just remember that the rows have to be inside the container that contains w3-container! -->
<!-- and they all can be nested! -->
<!-- here is the closing div that contains class w3-container! -->
</div> <!-- end page container -->
<!-- at this point all open div tags have been closed -->
<!-- so the grid system is very simple. -->
<!-- it only contains two classes: w3-container and w3-row -->
<!-- that's all! -->
<!-- anything inside the grid are just ordinary html elements: -->
<!-- div, p, span, etc. -->
<!-- as you can see from the above grid, -->
<!-- it contains only one w3-container and one w3-row -->
<!-- that's all! -->
<!-- here is the last section of the website: footer -->
<!-- start footer -->
<footer class="w3-container w3-theme-d3 w3-padding-16">
<div>Follow us on social medias: Facebook, Twitter, Instagram!</div>
<div class="w3-right">Contact: john@doe.com</div>
</footer>
<script>
// Accordion
function myFunction(id)
{
var x = document.getElementById(id);
if (x.className.indexOf("w3-show") == -1)
{
x.className += " w3-show";
x.previousElementSibling.className += " w3-theme-d1";
}
else
{
x.className = x.className.replace("w3-show", "");
x.previousElementSibling.className =
x.previousElementSibling.className.replace(" w3-theme-d1", "");
}
}
// used to toggle on smaller screen when clicking on the menu button
function openNav()
{
var x = document.getElementById("navDemo");
if (x.className.indexOf("w3-show") == -1)
{
x.className += " w3-show";
}
else
{
x.className = x.className.replace(" w3-show", "");
}
}
</script>
</body>
</html>
/* THIS ENDS THE WEBSITE DEMONSTRATION CODE */
/* The rest are just extra contents to help you learn more about programming */
/* Here is the listing of colors. see css file for more definitions */
/* Colors */
.w3-amber, .w3-hover-amber:hover{color:#000!important;
background-color:#ffc107!important}
.w3-aqua,.w3-hover-aqua:hover{color:#000!important;
background-color:#00ffff!important}
.w3-blue,.w3-hover-blue:hover{color:#fff!important;
background-color:#2196F3!important}
.w3-light-blue,.w3-hover-light-blue:hover{color:#000!important;
background-color:#87CEEB!important}
.w3-brown,.w3-hover-brown:hover{color:#fff!important;
background-color:#795548!important}
.w3-cyan,.w3-hover-cyan:hover{color:#000!important;
background-color:#00bcd4!important}
.w3-blue-grey,.w3-hover-blue-grey:hover,.w3-blue-gray,
.w3-hover-blue-gray:hover{color:#fff!important;
background-color:#607d8b!important}
.w3-green,.w3-hover-green:hover{color:#fff!important;
background-color:#4CAF50!important}
.w3-light-green,.w3-hover-light-green:hover{color:#000!important;
background-color:#8bc34a!important}
.w3-indigo,.w3-hover-indigo:hover{color:#fff!important;
background-color:#3f51b5!important}
.w3-khaki,.w3-hover-khaki:hover{color:#000!important;
background-color:#f0e68c!important}
.w3-lime,.w3-hover-lime:hover{color:#000!important;
background-color:#cddc39!important}
.w3-orange,.w3-hover-orange:hover{color:#000!important;
background-color:#ff9800!important}
.w3-deep-orange,.w3-hover-deep-orange:hover{color:#fff!important;
background-color:#ff5722!important}
.w3-pink,.w3-hover-pink:hover{color:#fff!important;
background-color:#e91e63!important}
.w3-purple,.w3-hover-purple:hover{color:#fff!important;
background-color:#9c27b0!important}
.w3-deep-purple,.w3-hover-deep-purple:hover{color:#fff!important;
background-color:#673ab7!important}
.w3-red,.w3-hover-red:hover{color:#fff!important;
background-color:#f44336!important}
.w3-sand,.w3-hover-sand:hover{color:#000!important;
background-color:#fdf5e6!important}
.w3-teal,.w3-hover-teal:hover{color:#fff!important;
background-color:#009688!important}
.w3-yellow,.w3-hover-yellow:hover{color:#000!important;
background-color:#ffeb3b!important}
.w3-white,.w3-hover-white:hover{color:#000!important;
background-color:#fff!important}
.w3-black,.w3-hover-black:hover{color:#fff!important;
background-color:#000!important}
.w3-grey,.w3-hover-grey:hover,.w3-gray,
.w3-hover-gray:hover{color:#000!important;
background-color:#9e9e9e!important}
.w3-light-grey,.w3-hover-light-grey:hover,.w3-light-gray,
.w3-hover-light-gray:hover{color:#000!important;
background-color:#f1f1f1!important}
.w3-dark-grey,.w3-hover-dark-grey:hover,.w3-dark-gray,
.w3-hover-dark-gray:hover{color:#fff!important;
background-color:#616161!important}
.w3-pale-red,.w3-hover-pale-red:hover{color:#000!important;
background-color:#ffdddd!important}
.w3-pale-green,.w3-hover-pale-green:hover{color:#000!important;
background-color:#ddffdd!important}
.w3-pale-yellow,.w3-hover-pale-yellow:hover{color:#000!important;
background-color:#ffffcc!important}
.w3-pale-blue,.w3-hover-pale-blue:hover{color:#000!important;
background-color:#ddffff!important}
.w3-text-amber,.w3-hover-text-amber:hover{color:#ffc107!important}
.w3-text-aqua,.w3-hover-text-aqua:hover{color:#00ffff!important}
.w3-text-blue,.w3-hover-text-blue:hover{color:#2196F3!important}
.w3-text-light-blue,.w3-hover-text-light-blue:hover{color:#87CEEB!important}
.w3-text-brown,.w3-hover-text-brown:hover{color:#795548!important}
.w3-text-cyan,.w3-hover-text-cyan:hover{color:#00bcd4!important}
.w3-text-blue-grey,.w3-hover-text-blue-grey:hover,.w3-text-blue-gray,
.w3-hover-text-blue-gray:hover{color:#607d8b!important}
.w3-text-green,.w3-hover-text-green:hover{color:#4CAF50!important}
.w3-text-light-green,.w3-hover-text-light-green:hover{color:#8bc34a!important}
.w3-text-indigo,.w3-hover-text-indigo:hover{color:#3f51b5!important}
.w3-text-khaki,.w3-hover-text-khaki:hover{color:#b4aa50!important}
.w3-text-lime,.w3-hover-text-lime:hover{color:#cddc39!important}
.w3-text-orange,.w3-hover-text-orange:hover{color:#ff9800!important}
.w3-text-deep-orange,.w3-hover-text-deep-orange:hover{color:#ff5722!important}
.w3-text-pink,.w3-hover-text-pink:hover{color:#e91e63!important}
.w3-text-purple,.w3-hover-text-purple:hover{color:#9c27b0!important}
.w3-text-deep-purple,.w3-hover-text-deep-purple:hover{color:#673ab7!important}
.w3-text-red,.w3-hover-text-red:hover{color:#f44336!important}
.w3-text-sand,.w3-hover-text-sand:hover{color:#fdf5e6!important}
.w3-text-teal,.w3-hover-text-teal:hover{color:#009688!important}
.w3-text-yellow,.w3-hover-text-yellow:hover{color:#d2be0e!important}
.w3-text-white,.w3-hover-text-white:hover{color:#fff!important}
.w3-text-black,.w3-hover-text-black:hover{color:#000!important}
.w3-text-grey,.w3-hover-text-grey:hover,.w3-text-gray,
.w3-hover-text-gray:hover{color:#757575!important}
.w3-text-light-grey,.w3-hover-text-light-grey:hover,
.w3-text-light-gray,.w3-hover-text-light-gray:hover{color:#f1f1f1!important}
.w3-text-dark-grey,.w3-hover-text-dark-grey:hover,
.w3-text-dark-gray,.w3-hover-text-dark-gray:hover{color:#3a3a3a!important}
/* can you make sense of the above color definitions? */
/* let's take the last color definition above: the last line! */
.w3-text-dark-gray,.w3-hover-text-dark-gray:hover{color:#3a3a3a!important}
/* format it like this for a better visualization: */
.w3-text-dark-gray,
.w3-hover-text-dark-gray:hover
{
color:#3a3a3a!important
}
/* there are two classes: one is w3-text-dard-gray and the other */
/* is w3-hover-text-dark-gray which is attached to a hover mouse event. */
/* both of these two classes are assigned a color of a dark-gray */
/* which is #3a3a3a */
/* disregard the word "!important" for now. you can learn more in */
/* the css tutorial provided by W3Schools */
/* if you decide to add your own css definition, just add them to */
/* the bottom of the w3.css file. */
/* for example, if you find that the pre-made colors provided by */
/* W3Schools are not enough to your liking, you can add more color */
/* definitions to w3.css file like this: */
.w3-slate-gray
{
/** don't forget to put "!important" as well! **/
color:#ebe2e1!important
}
/* you can add other definitions to w3.css file as well because */
/* w3.css is only a css file framework that contains the universal */
/* commonly used definitions. */
/* so you most certainly need to add your own css defitions to */
/* the w3.css file */
/* A SECRET TO MEMORIZING CSS ATTRIBUTES or PROPERTIES */
/* one of the most confusing things in CSS is memorizing */
/* attributes/properties */
/* what if you have an attribute that says: */
/* padding: 10px 5px 20px 10px */
/* what does that mean? */
/* it means the padding property has four values:
top padding is 10px
right padding is 5px
bottom padding is 20px
left padding is 10px
*/
/* so how do you remember them? */
/* by brute force? */
/* that's what most people do: remembering it by brute force! */
/* but there is an easier way to remembering them and here's how: */
/* first, think of all HTML elements as a box. well, to be honest */
/* all HTML elements (div, p, span, a, button, i, etc) are boxes! */
/* and boxes have four sides and four corners! */
/* when you style an HTML element using padding you actually are */
/* styling the four sides and four corners! */
/* note: all properties that receive dimension values, i.e., padding, */
/* padding-top (-bottom, -left, and -right), margin, */
/* margin-top (-bottom, -left, and -right), border, color, etc., have */
/* four sides and four corners! */
/* now back to the padding example! */
/* if you follow the definition above it says padding 10px 5px 20px 10px */
/* it basically tells you to follow the box sitting stationary upright */
/* think of it as an ordinary box that is square sitting stationary upright */
/* an ordinary square box has four sides and four corners */
/* starting from the top of the box, which is 10px in height, and then follow */
/* the box around (from left to right), which is to the right side of the box! */
/* the KEYWORD is "around" (around the box)! */
/* in the right side of the box is where you find a 5px wide space gap! */
/* now you're done with the top and the right side of the box, so you continue */
/* on "around" the box, which is to the bottom of the box containing 20px in */
/* height! */
/* do you see what's happening? */
/* you basically follow the box "around" until you end up at the same place that */
/* you started, which is at the top of the box sitting stationary upright */
/* remember that a box has four sides and four corners! */
/* so you need to follow the box around the four corners! */
/* now you're at the bottom of the box and you continue to follow */
/* the box around, which is to the left side of the box containing */
/* a 10px wide gap! */
/* There you have it! */
/* A secret to memorizing the CSS attributes! */
/* what if you have something like the following illustrations? */
/* the same thing: follow the box! well, sort of! but you get the idea!
if the padding property has three values:
padding: 25px 50px 75px;
top padding is 25px
right and left paddings are 50px
bottom padding is 75px
above, start at the top of the box and move to the right side of the box!
now since right and left are together, it is a common value for both!
from there, you continue on around the box until all four sides are met!
so it goes like this:
the browsers style it by first styling the top and then the right and the
left (together) and then finally the bottom and it needs not go to the left
because it already done so earlier!
if the padding property has two values:
padding: 25px 50px;
top and bottom paddings are 25px
remember the common sense of saying left and right are together?
well, the same thing is also true: top and bottom are together!
so right and left paddings are 50px
this is where the rule is broken and makes an exception, but still not
too far from the rule! but the common sense kicks in as well!
top and bottom go together and right and left also go together!
as you can see, you follow the same box rule logic!
and add common sense to it!
if the padding property has only one value:
padding: 25px;
all four paddings are 25px
this one is not obvious to the human eyes but the browsers style it
using the box rule by first styling the top and then the right and then
the bottom and finally the left side of the box using only one value!
YES, THIS IS TRUE THAT BROWSWERS FOLLOW THE BOX SHAPE AROUND!
Do you see how simple it is to remember something that is so hard?
*/
/* YOUR OWN CSS DEFINITIONS */
/* most likely you will need to create your own CSS definitions */
/* to fullfil your needs! */
/* when you create your own definitions make sure that you use your */
/* own prefix and not the 'w3' prefix so that to avoid conflict! */
/* the color, padding, margin size, and text size are probably the */
/* most definitions you might need to create to fullfil your needs! */
/* for example, in most cases, you might need to style the left side */
/* margin only by using a 'my-padding-left-10 or my-margin-left-20 or
whatever margin or padding size you need! for example:
.my-padding-left-10
{
/* here is where you specify the size */
padding-left:10px!important;
}
.my-margin-left-20
{
/* here is where you specify the size */
margin-left:20px!important;
}
*/
/* there you have it! */
/* please check out tutorials at the W3Schools.com for more */
/* on this topic! */
For more about colors, please see my tutorial called an introduction to colors!
To get your own color check this out: color picker!
As mentioned earlier, the best place to advance your programming skills is the W3Schools. One particular topic that you might want to spend some time on learning is the image tutorial. You can learn how to place background images on your website as well as learning how to make your images work on mobile devices. So there are lots of topics available for you to improve your programming skills.
While you're at it learning about images, you might want to spend some time learning this important CSS class that makes displaying images awesome. The CSS class is called "clearfix" and can be found here: https://www.w3schools.com/howto/howto_css_clearfix.asp
Also, while you're at it learning about CSS, you might find these topics interesting and useful as well. Check the following topics out:
Best Free JavaScript & CSS/CSS3 Libraries For Modern Web Design
For more good stuffs, particularly photo galleries, sliders and plugins, please check out these sites:
https://www.jqueryscript.net/ https://frontendscript.com/ Unslider Simplest Carousel Query LightSliderThe latter one is a very simple carousel slider that suites very well for beginning programmers to use and learn. Check it out and see the demo by clicking on the "Example" menu. Try it!!!
There you have it! So go at it!!!
First, you need to visit the websites (particularly jqueryscript.net, https://frontendscript.com, Unslider Simplest Carousel) mentioned above and browse through their sliders. Once you've decided which one you want, go ahead and download their plugin and go from there. Each plugin has a demo for you to see a preview of what it should look like. It also has a tutorial to help you incorporate it in your website.
For this tutorial, I chose one of the jquery slider plugin that I found on the Internet and it is called CarouFredSel. Here is the link to that plugin: https://github.com/DivaVocals/carouFredSel
If you want to use this plugin, you need to download the plugin from the link mentioned above and extract it. The plugin as usual comes in a zip package, so you definitely need a zip software installed on your computer to extract it. See instruction on zip application earlier at the beginning of this tutorial.
Once you'd downloaded and extracted it, you can view the demo contains in file index.html inside the main folder called 'carouFredSel-master'. Just double-click on the file index.html and it will activate a demo screen showing the various styles of the slider that you can use to incorporate in your own website.
Let's incorporate that plugin in the example website shown above.
File: index.php
<!DOCTYPE html>
<html>
<head>
<title>Template</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- include jQuery + carouFredSel plugin -->
<!-- right here where you link to a jquery library that -->
<!-- is hosted in a Content Delivery Network or CDN -->
<!-- a CDN is just a central data network that mainly delivering -->
<!-- data content to users via a link! -->
<script type="text/javascript" language="javascript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<!-- this CDN is owned by Google! -->
<!-- so Google is hosting the jquery library for everyone to link to -->
<!-- and use it instead of embedding that jquery library in their own script! -->
<!-- personally, I recommend that you embedd jquery library in your own -->
<!-- script instead of linking to a CDN! -->
<!-- to embedd a jquery library in your own script, do like the following -->
<!-- assuming you'd downloaded the jquery and place that library in a folder -->
<!-- called js/jquery -->
<script type="text/javascript" language="javascript"
src="js/jquery/jquery.min.js"></script>
<!-- to download the jquery library you -->
<!-- need to go to the jquery website: -->
<!-- https://jquery.com/download/ -->
<!-- click on the "Download the compressed, production" -->
<!-- and just hilight the whole file content and -->
<!-- copy and paste it in a blank file and name it accordingly! -->
<!-- in my case above, I named the jquery library file name to -->
<!-- 'jquery.min.js' -->
<!-- do not include both the CDN and the embedded library at the -->
<!-- same time because it might cause problems! -->
<!-- so use one or the other and not both of them at the same time! -->
<!-- next is the link to the carouFredSel library stored in the -->
<!-- plugin folder called carouFredSel-master -->
<script type="text/javascript" language="javascript"
src="jquery.carouFredSel-6.2.1-packed.js"></script>
<!-- optionally include helper plugins -->
<script type="text/javascript" language="javascript"
src="helper-plugins/jquery.mousewheel.min.js"></script>
<script type="text/javascript" language="javascript"
src="helper-plugins/jquery.touchSwipe.min.js"></script>
<script type="text/javascript" language="javascript"
src="helper-plugins/jquery.transit.min.js"></script>
<script type="text/javascript" language="javascript"
src="helper-plugins/jquery.ba-throttle-debounce.min.js"></script>
<link rel="stylesheet" href="./css/mobile.css">
<link rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.6.3/
css/font-awesome.min.css">
<link rel="stylesheet"
href="http://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/
3.2.0/css/bootstrap.min.css">
<script src="https://code.jquery.com/w3/1.4.5/jquery.w3-1.4.5.min.js">
</script>
<script type="text/javascript" src="js/bootstrap.min.js"></script>
<script type="text/javascript" src="javascript/javascript.js">
</script>
<!-- start plugin onDocumentReady -->
<script type="text/javascript" language="javascript">
$(function()
{
// Responsive layout, resizing the items
$('#foo4').carouFredSel(
{
responsive: true,
width: '100%',
scroll: 2,
items:
{
// the sliding content's width
// if you set it to half the
// screen size it will show two
// images at a time.
// if you set it to full screen
// (1000 pixels) it will show one
// image at a time.
width: 400,
// commenting out the optionally
// resize item-height option
// height: '30%',
visible:
{
min: 2,
max: 6
}
}
}
);
}
</script>
<style type="text/css" media="all">
.list_carousel
{
background-color: #ccc;
margin: 0 0 30px 60px;
width: 360px;
}
.list_carousel ul
{
margin: 0;
padding: 0;
list-style: none;
display: block;
}
.list_carousel li
{
font-size: 40px;
color: #999;
text-align: center;
background-color: #eee;
border: 5px solid #999;
width: 50px;
height: 50px;
padding: 0;
margin: 6px;
display: block;
float: left;
}
.list_carousel.responsive
{
width: auto;
margin-left: 0;
}
.clearfix
{
float: none;
clear: both;
}
.prev
{
float: left;
margin-left: 10px;
}
.next
{
float: right;
margin-right: 10px;
}
</style>
</head>
<body class="w3-theme-l5 w3-light-grey">
<!-- some of the following codes were broken down into multiple lines -->
<!-- to fit the screen display -->
<!-- Navbar -->
<!-- this is the div that wraps around the navbar -->
<div class="w3-top">
<div class="w3-bar w3-theme-d2 w3-left-align w3-small w3-blue">
<a class="w3-bar-item w3-button w3-hide-medium w3-hide-large w3-right
w3-padding-small w3-hover-white w3-small w3-theme-d2"
href="javascript:void(0);" onclick="openNav()">
<i class="fa fa-bars"></i></a>
<a href="#" class="w3-bar-item w3-button w3-padding-large w3-theme-d4">
<i class="fa fa-home w3-margin-right"></i>Logo</a>
<a href="#" class="w3-bar-item w3-button w3-hide-small w3-padding-large
w3-hover-white" title="News"><i class="fa fa-globe"></i></a>
<a href="#" class="w3-bar-item w3-button w3-hide-small w3-padding-large
w3-hover-white" title="Account Settings"><i class="fa fa-user"></i></a>
<a href="#" class="w3-bar-item w3-button w3-hide-small w3-padding-large
w3-hover-white" title="Messages"><i class="fa fa-envelope"></i>
<div class="w3-dropdown-hover w3-hide-small">
<button class="w3-button w3-padding-large" title="Notifications">
<i class="fa fa-bell"></i>
<span class="w3-badge w3-right w3-small w3-green">3</span>
</button>
<div class="w3-dropdown-content w3-card-4 w3-bar-block"
style="width:300px">
<a href="#" class="w3-bar-item w3-button">One new friend request</a>
<a href="#" class="w3-bar-item w3-button">John Doe posted on
your wall</a>
<a href="#" class="w3-bar-item w3-button">Jane likes your post</a>
</div>
</div>
<a href="#" class="w3-bar-item w3-button w3-hide-small w3-right
w3-padding-medium w3-hover-white" title="My Account">
<img src="./image/paul_tuon.jpg" class="w3-circle"
style="height:23px;width:23px" alt="Avatar"> </a>
</div>
</div> <!-- end div class="w3-top" -->
<!-- Navbar on small screens -->
<div id="navDemo" class="w3-bar-block w3-theme-d2 w3-hide
w3-hide-large w3-hide-medium w3-large">
<a href="#" class="w3-bar-item w3-button w3-padding-large">Link 1</a>
<a href="#" class="w3-bar-item w3-button w3-padding-large">Link 2</a>
<a href="#" class="w3-bar-item w3-button w3-padding-large">Link 3</a>
<a href="#" class="w3-bar-item w3-button w3-padding-large">My Profile</a>
</div>
<!-- now the navbar code is done! -->
<!-- at this point there are 0 open <div> tag -->
<!-- Slider Container -->
<div class="w3-container w3-content" style="max-width:1400px; margin-top:40px">
<div class="list_carousel responsive">
<!-- right here where the content of the slider is placed -->
<!-- notice that you can put any kind of content such as -->
<!-- text, images, etc., and as many content as you wish! -->
<!-- the slider will circle through the content until the end and loops -->
<!-- back to the beginning of the list! -->
<!-- the display of the images is dependenced on the size of the window -->
<!-- you set in the options of the function carouFredSel() above! -->
<!-- in the example above it was set to width: 400! -->
<ul id="foo4">
<li><img src="image/picture1.jpg"></li>
<li><img src="image/picture2.jpg"></li>
<li><img src="image/picture3.jpg"></li>
<li><img src="image/picture4.jpg"></li>
<li><img src="image/picture5.jpg"></li>
<li><img src="image/picture6.jpg"></li>
<li><img src="image/picture7.jpg"></li>
<li><img src="image/picture8.jpg"></li>
<li><img src="image/picture9.jpg"></li>
<li><img src="image/picture10.jpg"></li>
<li><img src="image/picture11.jpg"></li>
<li><img src="image/picture12.jpg"></li>
<li><img src="image/picture13.jpg"></li>
<li><img src="image/picture14.jpg"></li>
<li><img src="image/picture15.jpg"></li>
<li><img src="image/picture16.jpg"></li>
</ul>
<!-- for more tutorial on class "clearfix" please visit -->
<!-- https://www.w3schools.com/howto/howto_css_clearfix.asp -->
<div class="clearfix"></div>
</div>
</div>
<!-- Page Container -->
<div class="w3-container w3-content" style="max-width:1400px; margin-top:80px">
<!-- The Grid -->
<!-- here is the row! -->
<div class="w3-row">
<!-- Left Column -->
<div class="w3-col m3 w3-container">
<!-- Profile -->
<div class="w3-card w3-round w3-light-blue">
<div class="w3-container">
<h4 class="w3-center">My Profile</h4>
<p class="w3-center"><img src="./image/paul_tuon.jpg"
class="w3-circle" style="height:106px;width:106px"
alt="A Profile Picture"></p>
<hr>
<p><i class="fa fa-pencil fa-fw w3-margin-right
w3-text-theme"></i> Designer, UI</p>
<p><i class="fa fa-home fa-fw w3-margin-right
w3-text-theme"></i> Minneapolis, MN (US)</p>
<p><i class="fa fa-birthday-cake fa-fw w3-margin-right
w3-text-theme"></i> April 1, 2020</p>
</div>
</div>
<br>
<!-- Accordion -->
<div class="w3-card w3-round">
<div class="w3-pale-blue">
<button onclick="myFunction('Demo1')" class="w3-button
w3-block w3-theme-l1 w3-left-align">
<i class="fa fa-circle-onotch fa-fw w3-margin-right">
My Groups</i></button>
<div id="Demo1" class="w3-hide w3-container">
<p>Some text..</p>
</div>
<button onclick="myFunction('Demo2')" class="w3-button w3-block
w3-theme-l1 w3-left-align"><i class="fa fa-calendar-check-0
fa-fw w3-margin-right"> My Events</i></button>
<div id="Demo2" class="w3-hide w3-container">
<p>Some other text..</p>
</div>
<button onclick="myFunction('Demo3')" class="w3-button
w3-block w3-theme-l1 w3-left-align">
<i class="fa fa-user fa-fw w3-margin-right"> My Photos
</i></button>
<!-- class w3-container is used to hold the photos album layout -->
<!-- "My Photos" button! -->
<div id="Demo3" class="w3-hide w3-container">
<div class="w3-row-padding">
<br>
<!-- the following is where you put your photo album! -->
<!-- class w3-half is a grid layout as a two-column -->
<!-- layout relative to the class w3-container used -->
<!-- in the album layout so the photos are arranged -->
<!-- side by side as a two-column layout -->
<div class="w3-half">
<img src="./image/paul_tuon.jpg" style="width: 100%"
class="w3-margin-bottom">
</div>
<div class="w3-half">
<img src="./image/graduation.jpg" style="width: 100%"
class="w3-margin-bottom">
</div>
<!-- this is another two-column grid stacking below above -->
<div class="w3-half">
<img src="./image/paul_tuon.jpg" style="width: 100%"
class="w3-margin-bottom">
</div>
<div class="w3-half">
<img src="./image/graduation.jpg" style="width: 100%"
class="w3-margin-bottom">
</div>
<!-- this is another two-column grid stacking below above -->
<div class="w3-half">
<img src="image/example5.jpg" style="width: 100%"
class="w3-margin-bottom">
</div>
<div class="w3-half">
<img src="image/graduation.jpg" style="width: 100%"
class="w3-margin-bottom">
</div>
</div> <!-- end div class="w3-row-padding" -->
</div> <!-- end div id="Demo3" -->
</div> <!-- end div class="w3-white" -->
</div> <!-- end div class="w3-card w3-round" -->
<!-- this is the end of an accordion-like feature! -->
<!-- at this point there are still 3 open div -->
<!-- Interest: the miscellaneous content of interest! -->
<!-- w3-hide-small is to not display the content when mobile -->
<!-- device is used to load the web site! so "Interests" content -->
<!-- won't be loaded if mobile device is being used to load -->
<!-- this web site -->
<div class="w3-card w3-round w3-teal w3-hide-small">
<div class="w3-container">
<p>Interests</p>
<p>
<span class="w3-tag w3-small w3-theme-d5">News</span>
<span class="w3-tag w3-small w3-theme-d4">W3Schools</span>
<span class="w3-tag w3-small w3-theme-d3">Labels</span>
<span class="w3-tag w3-small w3-theme-d2">Games</span>
<span class="w3-tag w3-small w3-theme-d1">Friends</span>
<span class="w3-tag w3-small w3-theme">Games</span>
<span class="w3-tag w3-small w3-theme-l1">Friends</span>
<span class="w3-tag w3-small w3-theme-l2">Food</span>
<span class="w3-tag w3-small w3-theme-l3">Design</span>
<span class="w3-tag w3-small w3-theme-l4">Art</span>
<span class="w3-tag w3-small w3-theme-l5">Photos</span>
</p>
</div>
</div>
</div> <!-- end left column -->
<!-- at this point there are still 2 open <div> tags -->
<!-- start middle column -->
<div class="w3-col m7">
<!-- right here where I add some new content to the middle column -->
<!-- I add a scrolling message board to make it more flashy. for example: -->
<div class="w3-row-padding">
<!-- notice that you need to use the entire length of the grid: m12 -->
<!-- meaning the entire middle column -->
<div class="w3-col m12">
<div class="w3-card-2 w3-round w3-white">
<div class="w3-container w3-padding">
<marquee bgcolor=white width="100%" height="50">
<font size="5" color="#FF66FF">
Welcome to the 21st century and beyond where digital mobile rules!</font>
<font size="5" color="#1883FF">More content to scroll!</font>
</marquee>
</div>
</div>
</div>
</div>
<div class="w3-row-padding">
<div class="w3-col m12">
<div class="w3-card w3-round w3-white">
<div class="w3-container w3-padding">
<h6 class="w3-opacity">Social Media Template</h6>
<p contenteditable="true" class="w3-border
w3-padding">Status: Feeling blue!</p>
<button type="button" class="w3-button w3-theme">
<i class="fa fa-pencil"></i> Post
</button>
</div>
</div>
</div>
</div>
<div class="w3-container w3-card w3-round w3-blue w3-margin">
<img src="./image/paul_tuon.jpg" alt="Avatar" class="w3-left
w3-circle w3-margin-right" style="width:60px">
<span class="w3-right w3-opacity">1 min</span>
<h4>John Doe</h4>
<hr class="w3-clear">
<p>This is just an ordinary content! You can put whatever
content you want!</p>
<div class="w3-row-padding" style="margin:0 -16px">
<!--
<div class="w3-half">
<img src="./image/graduation.jpg" alt="just a picturer"
style="width: 100%" class="w3-margin-bottom">
</div>
<div class="w3-half">
<img src="./image/paul_tuon.jpg" alt="another picture"
style="width: 100%" class="w3-margin-bottom">
</div>
-->
</div>
<button type="button" class="w3-button w3-theme-d1 w3-margin-bottom">
<i class="fa fa-thumbs-up"></i> Like</button>
<button type="button" class="w3-button w3-theme-d2 w3-margin-bottom">
<i class="fa fa-comment"></i> Comment</button>
</div>
<div class="w3-container w3-card w3-round w3-khaki w3-margin"><br>
<!--
<img src="./image/graduation.jpg" alt="Avatar" class="w3-left
w3-circle w3-margin-right" style="width:60px">
-->
<span class="w3-right w3-opacity">16 min</span>
<h4>Jane Doe</h4>
<hr class="w3-clear">
<p>Lorem ipsum dolor. Lorem ipsum dolor. Lorem ipsum dolor.
Lorem ipsum dolor. Lorem ipsum dolor.</p>
<button type="button" class="w3-button w3-theme-d1 w3-margin-bottom">
<i class="fa fa-thumbs-up"></i> Like</button>
<button type="button" class="w3-button w3-theme-d2 w3-margin-bottom">
<i class="fa fa-comment"></i> Comment</button>
</div>
The following block of code contained in the original template
<!--
<div class="w3-container w3-card w3-round w3-lime w3-margin"><br>
<img src="./image/paul_tuon.jpg" alt="Avatar" class="w3-left
w3-circle w3-margin-right" style="width:60px">
<span class="w3-right w3-opacity">30 min</span>
<h4>Angie Jane
<hr class="w3-clear">
<img src="./image/gradution.jpg" class="w3-margin-bottom"
style="width:100%">
<p>Lorem ipsum dolor. Lorem ipsum dolor. Lorem ipsum dolor.
Lorem ipsum dolor. Lorem ipsum dolor.</p>
<button type="button" class="w3-button w3-theme-d1 w3-margin-bottom">
<i class="fa fa-thumbs-up"></i> Like</button>
<button type="button" class="w3-button w3-theme-d2 w3-margin-bottom">
<i class="fa fa-comment"></i> Comment</button>
</div>
-->
<!-- Accordion -->
<div class="mobile-card mobile-round">
<div class="mobile-pale-blue">
<button onclick="myFunction('group')"
class="mobile-button mobile-block mobile-theme-l1
mobile-left-align">
<i class="fa fa-circle-onotch fa-fw
mobile-margin-right"> My Groups</i>
</button>
<div id="group" class="mobile-hide mobile-container">
<p>Some text..</p>
</div>
<button onclick="accordion('event')"
class="mobile-button mobile-block mobile-theme-l1
mobile-left-align">
<i class="fa fa-calendar-check-0 fa-fw
mobile-margin-right"> My Events</i>
</button>
<div id="event" class="mobile-hide mobile-container">
<p>Some other text..</p>
<div>
<span class="hljs-string"><button onclick="accordion('photo')"
class="mobile-button mobile-block mobile-theme-l1
mobile-left-align"><i class="fa fa-user
fa-fw mobile-margin-right"> My Photos</i>
</button>
<div id="photo" class="mobile-hide mobile-container">
<div class="mobile-row-padding">
<br>
<div class="mobile-half">
<img src="./image/paul_tuon.jpg" style="width: 100%"
class="mobile-margin-bottom">
</div>
<div class="mobile-half">
<img src="./image/paul_tuon_graduation.jpg"
style="width: 100%" class="mobile-margin-bottom">
</div>
<div class="mobile-half">
<img src="./image/paul_tuon.jpg"
style="width: 100%" class="mobile-margin-bottom">
</div>
<div class="mobile-half">
<img src="./image/paul_tuon_graduation.jpg"
style="width: 100%" class="mobile-margin-bottom">
</div>
<div class="mobile-half">
<img src="image/paul_tuon.jpg"
style="width: 100%" class="mobile-margin-bottom">
</div>
<div class="mobile-half">
<img src="image/paul_tuon_graduation.jpg"
style="width: 100%" class="mobile-margin-bottom">
</div>
</div> <!-- end div class="mobile-row-padding" -->
</div> <!-- end div id="photo" -->
</div> <!-- end div class="mobile-pale-blue" -->
</div> <!-- end div class="mobile-card mobile-round" -->
<!-- end accordion style feature! -->
</div> <!-- end middle column -->
<!-- start right column -->
<!-- here it is: right column is 2/12 of the grid -->
<div class="w3-col m2">
<div class="w3-card w3-round w3-aqua w3-center">
<div class="w3-container">
<p>Upcoming Events:</p>
<img src="./image/image_105.jpg" class="w3-margin-bottom"
style="width:100%">
<p><strong>Holiday</strong></p>
<p>Friday 15:00</p>
<p><button type="button" class="w3-button w3-theme-14
w3-block">Info</button></p>
</div>
</div>
<div class="w3-card w3-round w3-pink w3-center">
<iv class="w3-container">
<p>Friend Request</p>
<!--
<img src="./image/graduation.jpg" class="w3-margin-bottom"
style="width:50%">
-->
<span>Jane Doe</span>
<div class="w3-row w3-opacity">
<div class="w3-half">
<button type="button" class="w3-button w3-block-14
w3-green w3-section" title="Accept">
<i class="fa fa-check"></i></button>
</div>
<div class="w3-half">
<button type="button" class="w3-button w3-block-14
w3-red w3-section" title="Decline">
<i class="fa fa-remove"></i></button>
</div>
</div>
</div>
</div>
<br>
<div class="w3-card w3-round w3-purple w3-padding w3-center">
<p>ADS</p>
</div>
<br>
</div> <!-- end right column -->
<!-- here is the closing div for class w3-row! -->
</div> <!-- end grid containing class w3-row -->
<!-- here is the closing div that contains class w3-container! -->
</div> <!-- end page container -->
<!-- here is the last section of the website: footer -->
<!-- start footer -->
<footer class="w3-container w3-theme-d3 w3-padding-16">
<div>Follow us on social medias: Facebook, Twitter, Instagram!</div>
<div class="w3-right">Contact: john@doe.com</div>
</footer>
<script>
// Accordion
function myFunction(id)
{
var x = document.getElementById(id);
if (x.className.indexOf("w3-show") == -1)
{
x.className += " w3-show";
x.previousElementSibling.className += " w3-theme-d1";
}
else
{
x.className = x.className.replace("w3-show", "");
x.previousElementSibling.className =
x.previousElementSibling.className.replace(" w3-theme-d1", "");
}
}
// used to toggle on smaller screen when clicking on the menu button
function openNav()
{
var x = document.getElementById("navDemo");
if (x.className.indexOf("w3-show") == -1)
{
x.className += " w3-show";
}
else
{
x.className = x.className.replace(" w3-show", "");
}
}
</script>
</body>
</html>
/* there you have it! */
/* a responsive mobile image slider */
/* when the website is loaded using a mobile */
/* device the slider showing one image sliding */
/* at a time! */
/* again, check out the plugin website mentioned earlier */
/* to find all kinds of plugins to use on your website! */
b
/* go at it! */
Fontawesome is a collection of ready-made images available to anyone for free. For a visual view on some examples of fontawesome images, go to my other website called "MondayThruSunday.COM," and look in all of the menu items and there should be a fontawesome in the front of the menu name for each menu item.
For example, for a menu name called "Home," there is a fontawesome image looking like a house in the front of the word "Home"; for a menu name called "Search," there is a fontawesome image looking like a magnifying glass in the front of the word "Search"; for a menu name called "Signup," there is a fontawesome image looking like three horizontal hash bars in the front of the word "Signup."
Fontawesomes are easy to use and most of all, you don't need to download them from somewhere and install them on your computer. They are available via the browser technology and the HTML.
To use fontawesomes, all you have to do is include the link to a CDN and then referring to its name as a class name inside your HTML element document -- the same way you refer to your CSS class names. See an illustration below.
Fontawesome images class starts with the word "fa fa-." For examples:
In the head <head> section of your HTML file, include the below link:
<link rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.6.3/css/font-awesome.min.css">
Again, a CDN (or Content Delivery Network) is just a central data
network that mainly delivering data content to users via a link!
Note that there are hundreds of CDNs out there that you can link to.
The above link is just one of those. Google has one and so does Bootstrap.
Here is a CDN from Bootstrap:
<link rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css">
So it is just a matter of preference of which CDN to use and all will work just fine!
After you included the link, you can refer to the font awesome images as
you normally would the same way you refer to a CSS class. For example:
In the body <body> section of your HTML file, do this:
<div class="fa fa-home"></div> will display an image of a house:
<div class="fa fa-home"> Home</div> will display: Home
<div class="fa fa-bars"></div> will display an image of three horizontal hash bars:
<div class="fa fa-search"></div> will display an image of a magnifying glass:
<div class="fa fa-check"></div> will display an image of a checkmark:
<div class="fa fa-globe"></div> will display an image of a globe:
<div class="fa fa-cart-arrow-down"></div> will display an image of a shopping cart:
<div class="fa fa-plus"></div> will display an image of a plus sign:
There are thousands of fontawesome images available on the Internet for free to use. Just Google the term "fontawesome" and it will give a lot of results to choose from.
Earlier, I mentioned that you don't need to download fontawesome images anywhere from the Internet. That is true for the standard fontawesome images that are provided by the World Wide Web consortium.
However, for thousands of specialized third party fontawesome images like specialized shopping cart [where you can customize the inter-activity of the cart] and others, you need to download them from the Internet and store them in your folders and refer to them accordingly.
All CDNs do the same thing: they gather all of the fontawesome images and store them in a directory on their server and provide a link to the public to link to.
For more about fontawesome tutorials, please check out this site: https://www.w3schools.com/css/css_icons.asp
Here is another excellent fontawesome tutorial: https://www.w3resource.com/icon/font-awesome/web-application-icons/cart-arrow-down.php
Here is the official site of the standard fontawesome consortium site: https://fontawesome.com/icons/cart-arrow-down
Here is the official site of the standard fontawesome consortium site that lists a fontawesome cheat sheet that you can basically find a particular fontawesome image quickly: https://fontawesome.com/cheatsheet?from=io
Here is an interesting topic that you might find very useful: CSS Badge
/** showing the number of items in the cart **/
/** here, assuming you have a shopping cart that has a **/
/** variable called $cart_count that holds the number of **/
/** items in the cart **/
cart<a href="#"><span class="badge" id="cart-count"><?=$cart_count?></span></a>
For more tutorial on "badge" please click on the link below!
As mentioned earlier multiple times, the best place to advance your programming skills is the W3Schools. One of the many topics that you might want to spend some time on learning is the "dialog modal" box tutorial that can be found here: https://www.w3schools.com/bootstrap/bootstrap_modal.asp. With the modal dialog box, you can put all kinds of content to make your users interact with it.
Here are some of the interesting topics that you might want to spend some time learning:
https://www.w3schools.com/bootstrap/bootstrap_carousel.asp https://www.w3schools.com/bootstrap/bootstrap_affix.asp https://www.w3schools.com/bootstrap/bootstrap_glyphicons.asp https://www.w3schools.com/bootstrap/bootstrap_pagination.asp https://www.w3schools.com/bootstrap/bootstrap_images.asp https://www.w3schools.com/css/css_image_gallery.asp https://www.w3schools.com/css/css3_text_effects.asp https://www.w3schools.com/html/html_entities.asp
So there are lots of topics available for you to improve your programming skills. So go at it!!!
When you program websites, you might run into situations that require you to be creative instead of using CSS to accomplish your tasks. One of the neat trick is to use non-breaking space command or to put some spaces between your content, as the "<marquee></marquee>" example below shows.
One is approximately equals to 10 pixels. As you can see in the example below, it requires a lot of to make the spaces wide enough.
The drawback of using instead of CSS is that it is very cluttered and messy; however, it is much quicker and easier than having to write CSS definitions.
Sometimes you can't write CSS definitions to fit your goal as in my case below. So you are left to use to accomplish the task.
Nonetheless, be very careful using instead of CSS because in mobile devices it might not display very well, especially if you have lots of .
So use it sparingly is the best way to use it. Don't over-use it!
In my case, it works very well on any mobile devices.
So there you have it! A very neat trick to use!!!
Here is a very simple trick to make your website looks awesome.
You won't see this trick anywhere in the document or tutorials
anywhere but only right here from me.
I use this trick on my own websites on a regular basis.
Here it is:
<div style="width: 700px; height: auto; background-color: #ffdddd;
padding: 5px 5px 5px 5px"><marquee>Content to scroll!</marquee>
</div>
The tag is called "<marquee></marquee>"
This simple tag scrolls continuously any content you put in it!
You can put this "<marquee></marquee>" tag anywhere as a
standalone or inside any HTML elements: <div>, <span>, <p>, etc.
You can also style your <marquee> content, such as
configuring the width and height and background color, etc.
Here is the same code that I use on my website: ZeroNilZilch.COM.
Notice that I embedded the styling code directly in the <marquee></marquee> as
appose to putting it in the <div></div> or other HTML elements.
It is just a personal preference and any HTML elements will work just fine.
As you can see, I had to use lots of to make enough spaces between contents!
The listing of between contents is a continuous line, but here,
it is broken down into multiple lines for displaying purpose!
<marquee bgcolor="white" width="100%" height="50">
<font size="5" color="#00FF99">www.ZeroNilZilch.COM</font>
<font size="5" color="#3333FF">Where the future is already here!</font>
<font size="5" color="#00FFFF">Explore, see the horizon,
open your mind and let your curiosity run wild,
discover, inspire and enrich your learning!!!</font>
<font size="5" color="#3333FF">The engine of your inginuity is limited only to
your imagination!!!</font>
<font size="5" color="#FF66FF">
Welcome to the 21st century and beyond where digital mobile rules!</font>
<font size="5" color="#1883FF">
This website and all of our affiliate sites are mobile-friendly!</font>
<font size="5" color="#00FFFF">
This means that you can use your mobile phones or any portable
small device to surf and shop with us conveniently and securely at all of our
affiliate sites!!!</font>
<font size="5" color="#FF66FF">They're built for the Millenials,
where all things Millenial, the Millenials' way!!</font>
<font size="5" color="#3333FF">Go ahead and fire up your smartphones and load
this website and see if it's mobile-friendly or not!</font>
</marquee>
Here are some more special characters to make your websites appear more useful. Please check this out:
Here is a very simple trick to make your texts appear vertically as well as other text effects that you might find useful. Please check these out:
https://www.w3schools.com/cssref/css3_pr_writing-mode.asp https://www.w3schools.com/css/css_align.asp https://www.w3schools.com/cssref/pr_text_text-decoration.asp https://www.w3schools.com/cssref/css3_pr_transform.asp https://www.w3schools.com/cssref/css3_pr_transition.asp https://www.w3schools.com/cssref/tryit.asp?filename=trycss_zindex
Here is a very simple trick to make your navigation bar works on mobile devices. On desktop it will display the menu items horizontally but on mobile devices, it will display them vertically.
Note that on mobile devices, the menu bar will be cleared all of menu items and a fontawesome fa fa-bars: is used instead in place of the menu items and the fa fa-bars is shown on the menu bar as a button to click.
When a user clicks on the fa fa-bars symbol it opens up the menu items listing the menu items vertically and neatly.
Using NAV tag, you don't need to do any special tricks to make it mobile-friendly: it is already built-in the browser technology.Just list your menu items to make it work on desktop devices as you normally would and the browser technology takes care of the mobile devices display behind the scene for you so that you don't need to do any special tricks:
https://www.w3schools.com/tags/tag_nav.aspThere you have it! A secret way to beautify your website!!!
Here is a very simple trick to make your website mobile-friendly. First of all, this is just a simple trick that is suited to some small situations where CSS is too complicated and too bulky to use. This trick works very well when you have a section of the code needs to handle small mobile devices and another section next to it can be used for desktop devices. For example:
<?php
/** this is a special trick that you'll never see from **/
/** any documentation or tutorials anywhere, period! **/
/** here is the special trick using a combination of PHP and Javascript: **/
echo "<script language='javascript'>
/** you need a space between the echo " and location **/
echo " location.href=\"${_SERVER['SCRIPT_NAME']}?${_SERVER['QUERY_STRING']}"
. "&width=\" + screen.width + \"&height=\" + screen.height;\n";
echo "</script>\n";
/** basically, the code above picks out the width and height **/
/** of the device using Javascript screen object and just **/
/** referring to the object's property: width and height! **/
/** very neat and simple! **/
/** the reference to 'location.href' is just reading the url's **/
/** incoming request and picking off the querystring at **/
/** the same time! **/
/** okay, let's see how it works! **/
/** first, you test the size of the device **/
/** in other words, when the browser hits this code above, **/
/** it checks to see what size the device is. **/
/** if it is a desktop device being used to surf this website, **/
/** it will execute the area of the code designed to be used on desktop! **/
/** if it is a mobile device being used to surf this website, **/
/** it will execute the area of the code designed to be used on mobile **/
/** devices **/
/** this is much simpler than having to write CSS definitions **/
/** it works just as good as if you had written a CSS definition to **/
/** do the job! **/
/** as a matter of fact, the groups that wrote the CSS rules to **/
/** make CSS definitions mobile-friendly used this same technique to **/
/** detect the devices to make their CSS rule do the job **/
/** of detecting the various mobile size! **/
/** they called it media definition that looks like this: **/
@media (max-width: 480px)
{
.nav-collapse
{
-webkit-transform: translate3d(0, 0, 0);
}
.page-header h1 small
{
display: block;
line-height: 20px;
}
}
/** but first, you need to test if the browser can read **/
/** the dimensions of the device being used to surf the webpage! **/
/** all browsers returns a width and height of the device being **/
/** used every time it loads the webpage! **/
/** but we need to use a special trick that you'll never see from **/
/** any documentation or tutorials anywhere, period! **/
/** here is a special trick using a combination of PHP and Javascript: **/
<?php
if (isset($_GET['width']) AND isset($_GET['height']))
{
global $width;
global $height;
// grab the geometry variables
$width = $_GET['width'];
$height = $_GET['height'];
if ($width > 600)
{
// desktop device! prepare code to be used on desktop!
?>
<!-- left column -->
<div class="mobile-col m3">
<!-- display left column content for desktop! -->
</div>
<!-- end left column -->
<!-- middle column -->
<div class="mobile-col m7">
<!-- display middle column content for desktop! -->
</div>
<!-- end middle column -->
<!-- right column -->
<div class="mobile-col m2">
<!-- display right column content for desktop! -->
</div>
<!-- end right column -->
<?php
} // end if $width > 600
else
{
// mobile devices! prepare code to be used on mobile devices!
// notice that inside this mobile section, you still need to
// use CSS to style the content to be mobile-friendly!
// I told you earlier that this simple trick doesn't do all of
// your mobile-friendly works! it does for certain situations only!
// you can use both this trick and CSS definitions to your advantage!
?>
<!-- left column -->
<div class="mobile-col m3">
<!-- display left column content for desktop! -->
</div>
<!-- end left column -->
<!-- middle column -->
<div class="mobile-col m7">
<!-- display middle column content for desktop! -->
</div>
<!-- end middle column -->
<!-- right column -->
<div class="mobile-col m2">
<!-- display right column content for desktop! -->
</div>
<!-- end right column -->
<?php
} // end else if $width > 600
} // end if (isset($_GET['width']) AND isset($_GET['height']))
else
{
// pass the geometry variables (preserve the original query string
echo "<script language='javascript'>\n";
echo " location.href=\"${_SERVER['SCRIPT_NAME']}?${_SERVER['QUERY_STRING']}"
. "&width=\" + screen.width + \"&height=\" + screen.height;\n";
echo "</script>\n";
// if for some reasons that the browser fails to grab the dimensions
// it will come here and you can handle that case accordingly!
// that situation is very rare! this code above always returns
// the dimensions!
// desktop device! prepare code to be used on desktop!
?>
<!-- left column -->
<div class="mobile-col m3">
<!-- display left column content for desktop! -->
</div>
<!-- end left column --<
<!-- middle column -->
<div class="mobile-col m7">
<!-- display middle column content for desktop! -->
</div>
<!-- end middle column -->
<!-- right column -->
<div class="mobile-col m2">
<!-- display right column content for desktop! -->
</div>
<!-- end right column -->
<?php
}
?>
There you have it!
A secret way to beautify your website by making it mobile-friendly!!!
Here is an interesting topic that you might find very useful: Tracking Visitors of Your Website
If you want to use the professionally-made tools and here are a few to choose from:
Paid Web Analytics Tools For Tracking Your Visitors
Web Analytics Tools For Tracking Your Visitors
10 Web Analytics Tools For Tracking Your Visitors
Here is my "barebone" simple code to track your visitors visiting on the index.php front page of your website. Any time a visitor visits your website, which is primarily being visited on the index.php front page, it tracks that person as one visit. If that person returns to visit your website again on another occassion on another session, it accounts for that visit as another one visit as well.
In other words, it logs each visit by a person as one visit no matter how many pages or area a visitor is visiting because this "barebone" simple code is designed to track only one page, which is the index.php front page. When a person continues to visit other pages on your website it does not account for those visits.
When a person leaves the website entirely and comes back to visit the website again, it again will log that person as one unique visit without differentiating the visit as a return visit. It keeps doing this for all other visitors as well.
It tallies all of the visits from all visitors [new or old visitors] that enter the website on every session to account for the website traffic. The total count of the page hits does not account for the return visits by the same person.
You can make improvement to this code as well or use it "AS IS" without any modification.
First of all, you will need to create a MySQL database to store all of your page hits.
To track your website traffic, just put all of the below code in a PHP file (perhaps, name it as pagehit.php) and then include this file name (pagehit.php) at the top of your index.php front page. See an example index.php front page later.
Remember that the following code is written to log only one page, which is assumed to be an index.php front page. So put the whole code below at the top of your index.php front page.
However, you can track page hits on every page of your website as well -- not just the index.php front page.
To count page hits on all of your website pages, just include this file name (pagehit.php) in every one of your pages. It will log different querystrings for different pages.
So the key thing to come away with this code (below) is that you can place the below code at the top of every page of your website if you want to track each page. However, it will distort your total page hits because a visitor may visits all of your pages and since each of your page contains a code to capture the page hit, the total page hit will be larger than it should be.
Let's put it this way: You want to track your website's unique traffic but if a visitor visits all of your pages or just some of your pages, the page hits will not reflect the true website's unique traffic. That's why this code below was designed to track only the index.php front page so that it accurately tracks the website's unique traffic.
So if you put the below code at the top of every page on your website it will just add all of the page hits together from all of your pages, including the index.php front page. In other words, it combines all of the page hits from all of your pages as one total and this total does not reflect the true unique traffic of the site.
So if you want to know which page got how many hits, you'll have to modify the code slightly because the code below just lump all of the various page hits together as one total, and this total includes the hits on the index.php front page, too.
Notice that you can either put the following code in a PHP file (pagehit.php) and include it like [include("pagehit.php")] in every page of your website OR just copy and paste the entire code and put it at the top of every page of your website and it will work just fine.
File: pagehit.php
<?php
/**
* a function to count how many times visitors visit a particular page
*
* you can call this function by passing a page file to it
*
* see at the bottom of this function to see how it is being called
*
* notice that argument $page can be any page on your website, but
* the database code just add all of the page hits together regardless
* of what page or pages you pass to it!
*
* this is where you can modify the database code slightly to store
* the different page hits individually! it's up to you to modify it!
*
* if you don't really care which page gets the most hit and only
* care about the whole website's total hit, then there is no need to
* modify this code! just use it "AS IS" and include the file
* pagehit.php at the top of the index.php front page and don't
* include this file in any of your pages because the index.php file
* is the only file we're tracking! nothing else!
*/
public function pageCounter($page, $referer)
{
// you might want to pass these connection parameters
// from external source instead of embedding them like here!
$hostingserver = 'root';
$databaseName = 'your_database_name';
$username = ''; // your database username
$password = ''; // your database password
// try to create a PDO connection instance
try
{
$conn = new PDO("mysql:host=$hostingserver;dbname=$databaseName",
$username, $password);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch (PDOException $e)
{
echo 'Cannot connect to the PDO database. ' . $e->getMessage();
}
// now try to create a table named pagecounter if it
// doesn't already exist in the database
// if it already exists in the database, it will skip this try/catch blocks!
// in other words, it won't create a table named `pagecounter` because
// it already exists in the database!
// however, it will continue executing all codes following the try/catch
// blocks!
// FYI:
// I've found that for some shared hosting's PDO engine doesn't
// recorgnize this statement:
// 'CREATE TABLE IF NOT EXISTS'
// to solve that problem, remove the below statement and create the table
// manually using PHPmyAdmin or some other means!
// so you don't actually need to test this condition (below) every time a
// page is hit! in other words, you don't need to check if the table
// exists or not, because you already know that a table already have been
// created; and therefore, there is no need to use the condition
// code below!
// just remove the create table condition below and make sure your table
// have been created already and it will work just fine!
try
{
$sql = $conn->prepare("CREATE TABLE IF NOT EXISTS `pagecounter`
(
`id` int(25) NOT NULL auto_increment,
`page_name` varchar(255) NOT NULL default '',
`referer` varchar(255) NULL default '',
`page_hit` int(25) NOT NULL default '0',
`date_time` datetime NOT NULL default
CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) TYPE=MyISAM"
);
// execute the query to create the table
$sql->execute();
}
catch (PDOException $e)
{
echo 'Cannot create table pagecounter. ' . $e->getMessage();
}
// after creating the table, it's time to insert new page hits
// but first, check to see if there are any page hits already stored
// in the database
$query = $conn->prepare("SELECT * FROM pagecounter
WHERE page_name = :page");
$result = $query->execute(['page' => $page]);
// check to see if there are any page hits already stored
// in the database
if ($result)
{
// yes, there are page hits already stored in the
// database!
$result->setFetchMode(PDO::FETCH_ASSOC);
while ($row = $result->fetch())
{
// so just add the new page hit to the total
$counter = $row['page_hit'] + 1;
}
// after adding a new page hit to the total,
// we need to update the total page hits and as well as
// updating the rest of the record, too!
$update = $conn->prepare("UPDATE pagecounter
SET page_name = :page,
referer = :referer,
page_hit = :counter");
$update->execute([':page' => $page,
':referer' => $referer,
':counter' => $counter
]
);
}
else
{
// this must be for the first page hit!
// there are no page hit stored in the database,
// so we need to store the first page hit in the database
$stmt = $conn->prepare("INSERT INTO pagecounter
VALUES (?, ?, ?)"
);
$stmt->execute([
'page_name' => $page,
'referer' => $referer,
// since there are no page hits stored in the
// database, so it must be the first time,
// and therefore, 'page_hit' is set to 1
'page_hit' => '1'
]
);
// if you observe the create table code definition
// and the insert table code above, you'll notice that
// there are 5 table fields in the create table code
// while only 3 fields (page_name, referer, and page_hit) are
// performed in the insert/update table code above.
// if you look closely in the create table definition
// you'll notice that the 'id' field contains the
// "auto_increment" clause that MySQL uses to increment
// this 'id' automatically starting with number 1 and
// increments it by 1 each time you insert a row of record.
// therefore, the 'id' field is not directly handled by
// programmers -- it is handled by MySQL automatically.
// likewise, the `date_time` field is not directly handled by
// programmers, either -- it is handled by MySQL automatically,
// because it was declared in the definition to use a
// 'default' date time value, generating a date and time
// automatically every time an insert or an update operation
// is taking place.
// the function CURRENT_TIMESTAMP generates the date and time
// automatically!
// so it looks like this:
// `date_time` datetime NOT NULL default CURRENT_TIMESTAMP
// self-explanatory!
// now on to the code flow:
// since this is the first time a visitor saw this
// page, we initialize the page to one hit!
// the next time any visitor visits this page it
// will not come here in the "else" condition because
// $result contains some value(s) for the tracking page!
$counter = 1;
}
// return the result of the query back to the caller!
// this is the number of times the page has been hit by visitors!
return $counter;
} // end function pageCounter($page, $referer)
/**
* now that the function has been written, we can call that function
* from anywhere!
*
* to call that function, you have to include the following snippet
* of code!
*
* put the following code at the top of every page you want to track!
*/
// HTTP headers
// every time the Web runs it fires off the HTTP protocol and PHP has a
// a built-in variable called $_SERVER to grab all of the HTTP headers.
// The superglobal array variable $_SERVER has 32 values, i.e.,
// $_SERVER['REMOTE_ADDR'], $_SERVER['HTTP_REFERER'], $_SERVER['SERVER_NAME'],
// $_SERVER['QUERY_STRING'], $_SERVER['SCRIPT_NAME'], $_SERVER['PHP_SELF'],
// $_SERVER['IP_ADDRESS'], $_SERVER['DNT'], etc.
// and you can view these values by running in your view (index.php)
// page or in any page output code like this:
// print_r($_SERVER);
// here, we grab the page's url using the HTTP protocol,
// particularly the built-in (superglobal) array variable $_SERVER.
// in here, we're just grabbing those HTTP headers, such as the URI or URL,
// including the querystrings. that's what the following code is doing!
// the $_SERVER['PHP_SELF'] code is to refer to the current file itself!
// so if you put $_SERVER['PHP_SELF'] inside a file called index.php, it
// will run that file!
// as for $_SERVER['SERVER_NAME'] is to grab the server name, i.e.,
// example.com.
// as for $_SERVER['HTTP_REFERER'] is to grab the url that the visitor
// just came from!
// for example, if a visitor came to your website from another website
// called http://www.example.com, $_SERVER['HTTP_REFERER'] returns
// http://www.example.com
// as for $_SERVER['QUERY_STRING'] is to grab the url's querystring, the
// string after the '?', i.e.,
// www.example.com/?arg1=value1&arg2=value2&arg3=value3
// so this will look something like these:
// www.example.com/index.php?arg1=value1&arg2=value2&arg3=value3
// www.example.com/catalog.php?arg1=value1&arg2=value2&arg3=value3
// www.example.com/affiliate.php?arg1=value1&arg2=value2&arg3=value3
// www.example.com/mypage.php?arg1=value1&arg2=value2&arg3=value3
/**
* here are some useful items you might find useful:
*
* $visitor_hour = date("h");
* $visitor_minute = date("i");
* $visitor_day = date("d");
* $visitor_month = date("m");
* $visitor_year = date("y");
*/
$self_url = $_SERVER['SERVER_NAME'] . $_SERVER['PHP_SELF'] . '?' .
$_SERVER['QUERY_STRING'];
// grab the url of the visitor's last link!
$referer = $_SERVER['HTTP_REFERER'];
// we call pageCounter() and getting a page hit instantly
$page_hit = pageCounter($self_url, $referer);
/**
* now that we have a page hit we can do whatever we want, such as
* display it somewhere on the same page. how you use this page hit
* is up to you, but here we just echoing out to the browser to
* display the page hit on the same page!
*/
echo $page_hit;
/**
* what if you want to put the display of the page hit somewhere
* on your website beside the default front index.php page?
*
* in other words, you want to put a hit counter in a different page
* other than the front index.php.
*
* in that case, you have to query the database using the code
* similar to the following. see a seperate index.php example below.
*
* you need to put this code at the very top of your xxx.php page!
*
* // try to create a PDO connection instance
* try
* {
* $conn = new PDO("mysql:host=$hostingserver;dbname=$databaseName",
* $username, $password);
* $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
* }
* catch (PDOException $e)
* {
* echo 'Cannot connect to the PDO database. ' . $e->getMessage();
* }
*
* $query = $conn->prepare("SELECT * FROM pagecounter
* WHERE page_name = :page");
*
* $result = $query->execute('page' => $page);
*
* if ($result)
* {
* $result->setFetchMode(PDO::FETCH_ASSOC);
* while ($row = $result->fetch())
* {
* $counter = $row['page_hit'] + 1;
* }
* }
*
* and then you can basically display the hit page anywhere on
* your xxx.php. for example:
*
* <p>Total visits: <?=$counter?>
*
* see the "barebone" index.php page below as an example!
*/
?>
The example above can be used to display in the "barebone" index.php front page as well.
Here is a "barebone" index.php front page example to show how to include the pagehit.php file at the top of your index.php front page.
File: index.php
?<php
// here, assuming you name the whole code above as pagehit.php
// this is it! just one line!
// very simple to include a tracking script on
// your index.php front page!
// don't forget to put the file pagehit.php at the same level
// in directory as your index.php
include(pagehit.php);
?>
<!DOCTYPE html>
<html lang="en-US">
<head>
<title>My Home Page</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="language" content="en" >
<link href="./asset/44ab1983/css/style.css" rel="stylesheet">
<script src="./asset/16eb9947/jquery.js"></script>
<style>
html,
body
{
width: 100%;
height: 100%;
background-color: #e6e6ff;
}
#product-item
{
background-color: white;
padding-left: 10px;
padding-right: 10px;
}
</style>
<script type="text/javascript">
$(document).ready(function()
{
public function example(arg)
{
// function code
}
});
</script>
</head>
<body>
<div>
content of the div
</div>
<div>
<table>
<tr>
<td>
td content
</td>
</tr>
</table>
</div>
<div>
content of the div
<a href="#">link</a>
</div>
</body>
</html>
There you have it! An easy way to track your website's visitors!!!
Now that you've got your website with all the bells and whistles, you can migrate it to your live server to make your website live online for your visitors all over the world to see.
There are plenty of web hosting providers out there: both for paid hosting and for free hosting. Just Google the term "free web hosting" and it will give you a lot of results to choose from.
Here is one that I found on the Internet, the one that I use on one of my websites: https://webfreehosting.net/
As with all free web hostings, there are certain things you can and can't do, such as you can't incorporating your payment application to do ecommerce transactions. To be able to do ecommerce transactions, you'll have to subscribe to their paid hosting service that normally costs about $2.99 per month.
For the free basic web hosting plan, you are limited to certain bandwidth as well. For example, according to the basic free plan (advertised as of June 2021), you're allowed only 5 GB of traffic usage per month. If your website generates traffic usage higher than 5 GB per month they will suspend your website for the remainding time for that particular month once your website reaches 5 GB.
Your website will come back online live at the beginning of the next month. Here is what a notification of the suspension look like if your website happens to generate usage traffic higher than the allowable 5 GB (as was the case for one of my websites called www.PostalJobHotline.COM which got the below suspension notification):
Warning: Account Suspended Due to Over-Traffic!
Your account has been temporarily suspended, because you have reached 5.16 GiB of traffic usage and your monthly allowance is 5 GiB. The traffic counter is reset at the end of the month and your account will be restored automatically. If you do not wish to wait that long and want to have your account and websites working please go to Buy Services Upgrade Services section and upgrade to a hosting plan with higher monthly traffic allowance.
So if for some particular month -- especially late in the month -- and you happen to go to one of my websites and you can't access it, it's probably it is being suspended due to over-traffic usage limit. Now you know why sometimes my websites are offline because of the suspension due to over-traffic usage limit.
Not only that, even if you have a paid hosting plan with them and if your website receives a lot of traffic, this hosting provider throttles your bandwidth to slow down your visitors visiting your website, making your website to load very slowly.
An example of that is my website ZeroNilZilch.COM, which receives very heavy traffic, and as a result, this hosting provider throttles my bandwidth, making it very slow to load. So much for a paid hosting plan, huh? Where is the benefit?
You may have already noticed that the website is very slow to load. This is because my website receives very very heavy traffic and this hosting provider throttles my bandwidth traffic.
So please be patience with my website when surfing my website and please keep visiting my website regularly when you need to. I would love to have you all continue making use of the resources in my website on a regular basis.
Thanks!!!
If you compare ZeroNilZilch.COM with the rest of my websites, say, Noon2Noon.COM, or Rainbow180.COM, or PostalJobHotline.COM, ZeroNilZilch.COM takes a long time to load while the others are very fast to load. This is due to this hosting provider throttles my loading speed because of ZeroNilZilch.COM generating very very heavy traffic.
As you can see, even when I follow their policy very religiously and not even anywhere close to breaking their policy, they still impose limits on my website, something that I'm not very happy about. So this is the only one factor that I'm not happy about this hosting provider.
So please read their policy. Also, you need to abide by their policy on all other aspects of the "free plan" to avoid being shut down. So make sure you read their policy on what you can do and on what you "CAN'T" do.
I hope you take this warning seriously because once you're shut down, you can't get another account with the same host provider. You'll have to find another hosting provider.
All hosting providers have policy that they enforce very strictly. So don't loose your hosting account with this hosting that I mentioned above, because it is one of the best hosting providers out there, albeit, they impose bandwidth limits when your website receives very heavy traffic.
I don't know if other shared hostings do this or not. Anyhow, please be mindful of this scenario.
So good luck and have fun with your website, albeit be mindful of the policies placed on your hosting plan.
Here is a secret that no one will tell you about this hosting provider mentioned above, but I will: You can actually signup for many hosting accounts with this hosting provider so that you can host as many (of your) websites as you want.
Yes, that is right; you can have your websites hosted by this hosting provider and it is perfectly legal and they won't ban you for hosting multiple websites on their platform. Yes, that is correct! You can host multiple websites on their platform! I repeat: You can host as many websites as you want on their plaform.
All you have to do is signup each account for each of your websites using a unique email address and it will let you signup for multiple accounts to host multiple websites.
My suggestion for you is to create multiple email accounts, say, with Gmail.COM or with any other email services and using those email addresses to signup hosting accounts with this hosting provider to host all of your websites.
Yahoo Mail is also one of the best emai service providers out there and it on par with Gmail service.
I, myself, use both Gmail and Yahoo Mail for my emails needs. I singed up multiple email accounts with both and the best part is that you can signup for an ulimited email accounts and also you can use the same personal information for all accounts as well, but the only requirement is that you need to use unique username, password, and of course, unique email address for each account.
For example, I currently have four Gmail accounts and three Yahoo Mail accounts and I used those email addresses that I signed up to signup for the free webhoting from the web hosting service provider mentioned above.
Remember that one email address is only good for one hosting account to host one website. So if you have multiple websites (as I do), you need to have multiple email addresses so that you can use those email addresses to signup hosting accounts with this hosting provider.
One email address is only good for one website.
You can use (your) same name and same address and the same other information as well.
You don't have to use different name and different other information.
Email address, username, password are the only ones that need to be unique for each account.
One Last Warning:
Please DO NOT abuse your free hosting priviledges. In other words, please read their 'Users Policies' carefully and obey their rules and guidelines.
Just because it is free and you can signup for multiple accounts, it doesn't mean that you can do anything you feel like doing.
So enjoy your multiple hosting accounts for your multiple websites, but be mindful of their rules and guidelines and DO NOT abuse your priviledges.
There you have it!
A secret that no one will tell you about it!!!
But I am telling you that!!!
So good luck and have fun with your websites, albeit be mindful of the policies placed on your hosting plans.
Once you'd signup an account with the above mentioned webhosting service provider, you can login to your account and the dashboard/webspace looks like the following:

On the left side is where it lists your account detail that looks like the following:

As you can see in the dashboard area or webspace area, you have several options to choose to go into more specific tasks. It shows all kinds of options for you to choose.
For example, when you click on an FTP Manager, it takes you to an FTP manager area where you can setup/create FTP accounts.
From there, you can fill out and supplying the various required FTP account information.
After creating an FTP account, now you're ready to upload your website files to your FTP account.
You will need these FTP account information to be used with your FileZilla application to transfer your files to and from your local computer to your FTP account.
See my other tutorial called Introduction to FileZilla.
Next, you need to create database(s) by clicking on the Database Manager and fill out the appropriate information. You will need these information to use with your database "PDO" connection.
See my other tutorial called Introduction to PDO.
At this point, you're done with creating FTP and Database accounts and presumably all your website files have been uploaded to your FTP account and your database tables and content have been created and setup and ready to go.
Next, you need to setup your domain. Look in your dashboard area for a topic called Domain Manager (similar to the one shown in the above illustration under topic called Website Manager). Click on that topic to go to setup your domain and it opens up a domain creation view that looks like the following:

In the above area where you can setup/create your domain accounts by supplying the necessary information.
There are several options to choose from depending on your actual situation. You can actually buy your own domain from this hosting provider on the spot by clicking on 'register a domain'. You can also transfer your domain to this hosting provider if you had registered it with some other domain registrars.
Either way, you're good to go with this hosting provider.
Personally, I recommend you to register your domain with other hosting/domain service providers that can offer you cheap domains. There are plenty of cheap domain service providers out there and one that I use personally is called https://www.namesilo.com/
If you're using domain from other domain service providers, just type the name of your domain in the box under: 'Host an existing Domain', for example: myfirstsite.com. And click on "Host Domain" button. Don't forget to put the "DOT" suffix name after your domain as shown in the example. This can be .com, .net. .org, etc.
If you're using a domain from other domain service providers, make sure that the domain is fully active, otherwise, this hosting is not able to detect your domain from the central server of the World Wide Web Consortium who actually is maintaining the domains as a central location.
The domain service providers are just third parties sellers selling domains from the main body organization called the World Wide Web Consortium.
What really is going on is that this hosting provider checks to see if the domain name that you entered on the input box is registered under your name listed on the World Wide Web Consortium database. The World Wide Web Consortium maintains all domain names in its database.
If the domain you entered is found in the WWWC database and it is registered in your name, then this hosting provider will host your domain in their web server. Otherwise, a message stating the reason as to why your domain is denied hosting.
After that, it should give you some sort of result at the bottom of your domain space if it is hosted successfully with this hosting provider.
In the result that you just created and hosted successfully, look at the heading at the far right side that says "Settings" and click on that topic. It should slides down to reveal more content. Now click on the topic: "DSN" (stands for 'Domain Name Server') and it should slides down further to reveal more content on that topic.
There are lots of options for you to choose, but for beginners, you only need to be concern with the topic called "NS".
Next, look under the heading called "Type" on the left side and scan down to find "NS" which stands for 'Name Server', or short for 'Domain Name Server'.
You need to copy this domain name server (address) so that you can use it to link your domain that you had registered with other domain service provider to your hosting account with this hosting service provider.
In a simplier way of saying is that, this domain name address is used to link your domain name that is residing in your third party domain registrar (or more specifically, residing in the WWWC database) to this web hosting provider. Your third party domain registrar needs this information to link the two servers together.
For example, if you had registered your domain name with other companies, (i.e., namesilo.com), you need to copy this 'Name Server' from this hosting provider and take it to your domain name registrar (namesilo.com) to link it to your domain name stored in the database in the WWWC.
This 'Name Server' will link to your domain name stored in the WWWC database. But you have to link it through your domain registrar.
Once you have the domain name server address (from this hosting provider), you need to go back to your domain service provider that you had registered and had an account with and login to that account so that you can supply this "NS" information to that domain registrar.
In your (third party) domain service provider/registrar's dashboard space, there should be an option that says "Domain Manager" and you need to navigate to that domain manager space and look for some sort of topic called "domain service name entry" or similar to that nature and then supply the "NS" information to it accordingly.
Hint: In your third party domain service registrar, look in the "Domain Manager" and click on one of the options listed on your particular domain. Maybe try clicking on the name of your domain and see what options it reveals.
Different domain service providers have slightly different look and feel, but all of them should have something in common, and that is, a box for you to enter the "NS".
Here is an example of domain entries:
Name Server 1: ns1.example.com
Name Server 2: ns2.example.com
Name Server 3: ns3.example.com
Name Server 4: ns4.example.com
Name Server 5: ns5.example.com
Each of these domain name servers represents one independence server that the company owns. Web hosting providers often have multiple servers so that if one goes down there are some backup servers ready to take over.
For example, this (fake) web hosting company called www.example.com has five servers: ns1, ns2, ns3, ns4, ns5.
As you can see above, there are several domain name servers that you need to enter, but for most hosting providers like the free web hosting service provider that I mentioned above, you only need to supply only two "NS" entries are enough.
In actuality, you're really using only one domain name server: ns1. The second one is just a backup in case the first is down or having problem. These days, servers are very reliable and one server is enough. So take two domain servers to your domain registrar (usually the first two: ns1 and ns2).
Once you've entered the "NS" information and submitted, it will take about 12 hours to take effect, although some domain providers take longer or shorter.
Meanwhile, after about an hour or so after you've submitted your "NS" information, you can try to load your website to see if it's effective or not. I've found that with most domain service providers, it only takes about one hour to take effect and not more. Try it after an hour of the entry and see if it is effective.
At this point, everything has been covered to enable you beginning website developers to able to create websites and host them in a live server. You can keep making improvements to your websites as they get more sophisticated.
There you have it! Have fun with your websites!
<?php
class Foo{
public test($x) {
if ($x == 1){
// do something with $x
}elseif ($x == 2){
// do something with $x again
}elseif ($x == 3){
// do something with $x again
}else{
// do nothing with $x
}
}
private getFoo(){
for ($i = 1; $i < 10; ++i){
// do something with $i
}
}
}
?>
<?php
class Foo
{
private $arr;
public function config()
{
return [
'id' => 'app',
'basePath' => dirname(__DIR__),
'component' => [
'request' => [
'csrf' => 'csrf-app',
],
'user' => [
'identity' => 'app\model\User',
'autoLogin' => true,
'cookie' => [
'name' => 'id-app',
'httpOnly' => true
],
'error' => [
'action' => 'site/error',
],
],
],
];
} // end config()
public function example($arg1 = null, $arg2 = null)
{
if (!empty($arg1))
{
// do something with $arg1
foreach ($arg1 as $item)
{
// do something with $item
try
{
switch ($item)
{
case 1:
// do something
if ($something)
{
for ($i = 0; $i < $something; $i++)
{
$dosomething[$i] = getSomething();
}
}
elseif ($otherThing)
{
foreach ($otherThing)
{
try
{
$doOtherThing = getOtherthing();
}
catch (Exception $e)
{
// doOtherThing with $e;
}
catch (OtherException $o)
{
// doOtherThing with $o
}
} // end foreach
} // end elseif ($something)
break;
case 2:
// do something
break;
case 3:
// do something
break;
default:
// do something
break;
} // end switch
} // end try
catch (Exception $e)
{
// Error! Do something with the error $e
}
} // end foreach
} // end if $arg1 is not empty
elseif ($arg2 != null)
{
// do ... while and for() loops
$test = false;
do
{
for ($i = 0; $i < count($arg2); ++$i)
{
if ($arg2[$i] == 1)
{
$test = true;
break;
}
} // end for()
} // end do
while ($test == false);
} // end elseif
else
{
// do nothing
return '';
}
$connect = '';
$attempt = 3;
while (!$connect AND $attempt > 0)
{
$authConn->connect();
$connect = $authConn->isConnect();
$attempt = $attempt - 1;
}
} // end example()
} // end class Foo
?>
<?php
class Foo
{
public addValue($x, $y)
{
// method body
} // end addValue()
private getFoo()
{
// method body
} // end getFoo()
} // end class Foo
?>
Notice the comments: // end addValue(), // end getFoo(), // end class Foo
<?php
class Foo
{
if ($expr1)
{
// lengthy multiple statements code block
// lengthy multiple statements code block
// lengthy multiple statements code block
} // end if ($expr1)
elseif ($expr2)
{
// lengthy multiple statements code block
// lengthy multiple statements code block
// lengthy multiple statements code block
} // end elseif ($expr2)
else
{
// lengthy multiple statements code block
// lengthy multiple statements code block
// lengthy multiple statements code block
} // end else if ($expr2)
try
{
// lengthy multiple statements code block
// lengthy multiple statements code block
// lengthy multiple statements code block
// lengthy multiple statements code block
} // end try block
catch (Exception $e)
{
// lengthy multiple statements code block
} // end Exception $e
catch (OtherException $o)
{
// lengthy multiple statements code block
} // end OtherException $o
} // end class Foo
?>
Notice the comments:
// end if ($expr1), // end elseif ($expr2), // end else if ($expr2)
// end try block, // end Exception $e, // end OtherException $o
// end class Foo
[...elements...] is used instead of the regular long form array(...elements...). And (shorthand) arrays used in the configurations can optionally contain a comma (",") as well at the end of the array element list. As examples, the below configurations contain a comma following the last array element [particularly 'charset => utf8' for shorthand array] even though there isn't another array element following it.
As a matter of fact, both regular arrays and shorthand arrays can contain a comma (",") at the end of the array element list. This is legal (for both) and you can choose to put it there or take it out and it is perfectly fine. It's not a requirement to have a comma at the end of the last array element. So it's up to your personal preference.
However, this coding standard strongly recommends putting a comma after all array elements because it avoids bugs. The reason that it is legal to have a comma after the last array element is to speed up coding process and avoid bugs. So it is strongly suggested that you put a comma after the last array element to avoid bugs.
Here is a snippet of code using the regular array:
$requirement = array(
array(
'name' => 'PHP Some Extension',
'mandatory' => true,
'condition' => extension_loaded('some_extension'),
'by' => 'Some application feature',
// notice the comma after this last array element!
'memo' => 'PHP extension "some_extension" required',
), // <== notice the comma! this is perfectly legal!
);
In the following, a configuration is used to create and initialize a database connection. Notice the comma following the array element 'charset => utf8' even though there isn't another array element following it:
$config = [
'class' => 'core\db\Connection',
'dsn' => 'mysql:host=127.0.0.1;dbname=demo',
'username' => 'root',
'password' => '',
'charset' => 'utf8', // <== notice the the comma! it's perfectly legal!
];
$db = core::createObject($config);
If you look at the example preview earlier [in the function config()], you'll see shorthand arrays are being used and all last elements of the arrays have a comma after each of the last element of the arrays. So it is definitely recommended that shorthand arrays and a comma on the last element of the array are being used -- on your own programming chores -- because it is much cleaner and easier to visualize, and most importantly, it speeds up your application development by eliminating bugs and unnecessary syntax corrections.
$a = $b + $c; // add b to c Do not do this: $a=$b+$c; //add b to c if ($b == $c) Do not do this: if($b==$c) Do not do this: for($i=0;$i<10;$i++) Do this instead: for ($i = 0; $i < 10; $i++)
class Example
{
}
That looks very good, but on longer reserved/keywords like public, private, protected, static, etc., it looks awful. For examples:
public class Example
{
}
private class Example
{
}
protected class Example
{
}
static class Example
{
}
Or for conditional structures:
if (condition)
{
}
else
{
}
elseif
{
}
foreach
{
}
As you can see, indenting four spaces for all code structures, [although very uniformed], is a bad idea, and it looks weird visually and logically. That's why I chose to indent the code according to the length of the reserved keyword.
class Example {
private $myVar;
public myMethod($x) {
// ... code
return $x; }
// ... more class code here!
}
Nowaday, the trend is leaving the legacy style behind and more and more programmers are adopting new modern style of coding and my coding convention is a byproduct of the new trend. So do these instead:
<?php
class Foo
{
/**
* class body declaration.
* notice the four spaces indentation of the class' opening "{" and
* the five spaces indentation of the method declaration: public.
* notice also that the opening/closing parentheses are aligned vertically at the
* same level, and all respective code body are inside the parentheses.
* it looks very clean and easy to follow the logic of the code flow.
*/
public $arr = array();
private $dbConnection;
public addValue($x, $y)
{
// method body
// notice that the indentation and placement of the opening "{" and
// closing "}" directly leveled with the last letter of its keyword.
}
private getFoo()
{
// method body
// notice that the indentation and placement of the opening "{" and
// closing "}" directly leveled with the last letter of its keyword.
}
protected getBar()
{
// method body
// notice that the indentation and placement of the opening "{" and
// closing "}" directly leveled with the last letter of its keyword.
}
// this is ok, too, and is preferred, indent five spaces to align with
// 'public' which is the most commonly use visibility clause
protected setFoo($x)
{
// method body
}
public addFoo()
{
// method body
}
// this is ok
abstract protected function zeroBar();
{
// method body
}
// this is ok, too, indent five spaces to align with 'public' which is
// the most commonly use visibility clause
abstract arrayHelper()
{
// code body here for this abstract method
}
public static function bar()
{
// method body
}
// this is ok, too
private static function bar()
{
// method body
}
// this is ok, too, indent five spaces
private static function bar()
{
// method body
}
final public static function bar()
{
// method body
}
// same as above
final private static function bar()
{
// method body
}
static function bar()
{
// method body
}
// this is ok, too
function bar()
{
// method body
}
// this is ok, too, indent five spaces to align with 'public'
function bar()
{
// method body
}
// this is ok, too, because it has at least five spaces indented for body code
function bar()
{
// code body.
// notice the placing of "{}" at the same level as the method declaration.
// notice also the indented five spaces for coding statements
// starting position
// .....
}
} // end class body
?>
trait ArrayHelper
{
// main body code of a trait
}
CSS: For CSS and other languages (such as Javascript, Java, C#, C/C++, etc.) do
follow the guideline outlined in this coding standard and follow a five-space rule
to align with 'public' visibility clause. For examples:
<style>
html,
body
{
width: 100%;
height: 100%;
background-color: #e6e6ff;
}
#product-item
{
background-color: white;
padding-left: 10px;
padding-right: 10px;
}
div .some-selector
{
background-color: white;
width: 400px;
height: 200px;
}
.nav li > form > button.logout
{
padding: 15px;
border: none;
}
a.asc:after, a.desc:after
{
position: relative;
top: 1px;
display: inline-block;
font-family: 'Glyphicons Halflings';
font-style: normal;
font-weight: normal;
line-height: 1;
padding-left: 5px;
}
a.asc:after
{
content: "\e151";
}
a.desc:after
{
content: "\e152";
}
</style>
<script type="text/javascript">
$(document).ready(function()
{
public function example(arg)
{
// function code
}
// this is ok, too
function example(arg)
{
// function code
}
// this ok, too, to align with 'public'
function example(arg)
{
// function code
}
// this ok, too
static public function example(arg)
{
// function code
}
});
</script>
<!DOCTYPE html>
<html lang="en-US">
<head>
<title>Untitled</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="language" content="en" >
<link href="./asset/44ab1983/css/style.css" rel="stylesheet">
<script src="./asset/16eb9947/jquery.js"></script>
<style>
html,
body
{
width: 100%;
height: 100%;
background-color: #e6e6ff;
}
#product-item
{
background-color: white;
padding-left: 10px;
padding-right: 10px;
}
</style>
<script type="text/javascript">
$(document).ready(function()
{
public function example(arg)
{
// function code
}
});
</script>
</head>
<body>
<div>
content of the div
</div>
<div>
<table>
<tr>
<td>
td content
</td>
</tr>
</table>
</div>
<div>
content of the div
<a href="#">link</a>
</div>
</body>
</html>
<?php
if ($expr1)
{
// single statement block. notice the use of braces even though it is not required!
}
elseif ($expr2)
{
// elseif code block. single statement block
}
elseif ($expr3)
{
// multiple statements code block
// multiple statements code block
// multiple statements code block
}
else
{
// else single statement block code block
}
<?php
switch ($expr)
{
case 0:
echo 'First case, with a break';
break;
case 1:
echo 'Second case, which falls through';
// no break
case 2:
case 3:
case 4:
echo 'Third case, return instead of break';
return;
default:
echo 'Default case';
break;
}
<?php
while ($expr)
{
// structure of code block
}
<?php
do
{
// structure of code block;
}
while ($expr);
<?php
do
{
// structure of code block;
}
while ($expr);
<?php
for ($i = 0; $i < 10; $i++)
{
// for code block
}
<?php
foreach ($iterable as $key => $value)
{
// foreach code block
}
<?php
try
{
// try code block
}
catch (FirstExceptionType $e)
{
// catch code block
}
catch (OtherExceptionType $e)
{
// catch code block
}
<?php
$closureWithArg = function($arg1, $arg2)
{
// body
};
<?php
$longArg_noVar = function(
$longArgument,
$longerArgument,
$muchLongerArgument
)
{
// code body
};
$noArg_longVar = function()
use(
/* notice naming variables using enumerated variables, */
/* although $longVar1 is fine */
$longVar1,
/* notice naming variables using enumerated variables, */
/* although $longVar2 is fine */
$longerVar2,
/* notice naming variables using enumerated variables, */
/* although $longVar3 is fine */
$muchLongerVar3
)
{
// code body
};
$longArg_longVar = function(
$longArgument,
$longerArgument,
$muchLongerArgument
)
use(
// readability: indents some spaces
$longVar1,
$longerVar2,
$muchLongerVar3
)
{
// code body
};
// this is ok too
$longArg_shortVar = function(
$longArgument,
$longerArgument,
$muchLongerArgument
) use($var1)
{
// code body
};
// this is ok, too
$shortArg_longVar = function($arg) use(
$longVar1,
$longerVar2,
$muchLongerVar3
)
{
// code body
};
<?php
$foo->bar(
$arg1,
function($arg2) use($var1)
{
// code body
},
$arg3
);
<?php
// PHP 5.3 and later:
namespace Vendor\Model;
class Foo
{
// code block
}
<?php
// PHP 5.2.x and earlier:
class Vendor_Model_Foo
{
// code block
}
<?php
namespace Vendor\Model;
class Foo
{
const VERSION = '1.0';
const DATE_APPROVED = '2012-06-01';
}
<?php
namespace Vendor\Package;
use FooInterface;
use BarClass as Bar;
use OtherVendor\OtherPackage\BazClass;
class Foo extends Bar implements FooInterface
{
public function sampleFunction($a, $b = null)
{
if ($a === $b)
{
bar();
}
elseif ($a > $b)
{
$foo->bar($arg1);
}
else
{
BazClass::bar($arg2, $arg3);
}
}
final public static function bar()
{
// method body
}
}
Both class and object have the same meaning and both achieve the same purpose but differ only in the way they're implemented and used.
A class consists of constant variables, properties, and methods. Those are the three basic attributes of a class. That's all a class is: it has three attributes -- a very simple concept and yet very powerful.
Consider the following class definition:
<?php
class MyClass
{
/**
* 1st attribute of the class MyClass:
*
* the purpose of the 1st attribute of the class is to store content values that are
* constant and can't change its values during the lifecycle of the application
*
* as you can see below, the constant variables (declared in uppercase letters) are
* called COMMAND_BEFORE_START, COMMAND_AFTER_START, COMMAND_EVENT_START, COMMAND_MESSAGE.
*
* their constant values are: before_start, after_start, command_start, etc., respectively.
*
* these values: before_start, after_start, command_start, et al, cannot change during the
* lifecycle of the application. they are constant values that cannot change!
*/
// declaring class constant variables
// COMMAND_EVENT_START, COMMAND_BEFORE_START, COMMAND_AFTER_START are constant variables
// command_start, before_start, after_start are constant values
// this value 'before_start' will not change during the lifecycle of the application
const COMMAND_BEFORE_START = 'before_start';
// this value 'command_start' will not change during the lifecycle of the application
const COMMAND_EVENT_START = 'command_start';
// this value 'after_start' will not change during the lifecycle of the application
const COMMAND_AFTER_START = 'after_start';
// this value: 'An object is just a copy of the class.'
// will not change during the lifecycle of the application
const COMMAND_MESSAGE = 'An object is just a copy of the class.';
/**
* 2nd attribute of the class MyClass:
*
* the purpose of the 2nd attribute of the class is to store content values that are
* constantly changing (its values) during the lifecycle of the application.
*
* as you can see below, the property variables (declared with visibility control) are:
* $make, $model, $color.
*
* these property variables can and do change during the lifecycle of the application,
* even though, they are initialized with the initial values in the same fashion as the
* 1st attribute constants (which are initialized with the initial constant values).
*
* the difference is that the 1st attribute variable values cannot change while the 2nd can.
*
* you'll see in the example code shown later that these 2nd attribute variables
* get assigned new values every time a constructor is called.
*
* so all 2nd attribute property variables often get their values change frequently during
* the lifecycle of the application.
*
* these 2nd attribute property variables must be declared prefacing with visibility control:
*
* public, protected, private
*
* public, protected, private are called visibility control or access control.
*/
public $make = 'Toyota'; // this value 'Toyota' will change during the lifecycle of the application
protected $model = 'Tundra'; // this value 'Tundra' will change during the lifecycle of the application
private $color = 'grey'; // this value 'grey' will change during the lifecycle of the application
/**
* 3rd attribute of the class MyClass:
*
* the purpose of the 3rd attribute of the class is to calculate and manipulate
* the content values that contain in the 1st and 2nd attribute property variables.
*
* you'll see in the example code shown later that the 3rd attribute's purpose is to
* calculate and manipulate the values contain in the 1st or 2nd attribute variables.
*
* likewise, these 3rd attribute methods and functions must be declared prefacing with
* visibility control: public, protected, private
*
* public, protected, private are called visibility control or access control.
*
* in this example class definition, we have two (3rd) attributes that manipulate or
* display messages.
* notice in the constructor, the 2nd attribute values get assigned to new values constantly.
*
* For example:
*/
// notice that you can pass in whatever make, model, or color to this constructor
public function __construct($make, $model, $color)
{
// notice that this constructor, which is also a member of the 3rd attribute type, calculates and
// manipulates the content values that contain in the 1st and 2nd attribute property variables.
// $this refers to the current object or class, which is 'MyClass'
// make refers to this class MyClass' property $make declared above
$this->make = $make;
// model refers to this class MyClass' property $model declared above
$this->model = $model;
// color refers to this class MyClass' property $color declared above
$this->color = $color;
}
public function test1()
{
// notice that this function test1(), which is also a member of the 3rd attribute type, calculates and
// manipulates the content values that contain in the 1st and 2nd attribute property variables.
// $this refers to the current object or class, which is 'MyClass'
// will output: An object is just a copy of the class.
echo $this->COMMAND_MESSAGE;
// will output whatever string got passed in via the constructor, for example: Ford
echo $this->make . ", ";
// will output whatever string got passed in via the constructor, for example: F-150
echo $this->model . ", ";
// will output whatever string got passed in via the constructor, for example: Grey
echo $this->color;
}
public function test2($str)
{
// notice that this function test2(), which is also a member of the 3rd attribute type, manipulates and
// displays the content values that contain in the 1st and 2nd attribute property variables.
// will output whatever string got passed in via $str
echo $str . "\n";
}
}
?>
And then consider the following object creation using the keyword new, which mean to create an instance of a class -- or to create a copy or a clone of a class.
$str = 'An object is just a copy of the class.';
// notice that the keyword new means to create an instance of a class -- or to create a copy or a clone of a class
// creating an instance of MyClass()
// $obj is an instance of the class MyClass. it is a copy or a clone of MyClass.
$obj = new MyClass();
$obj->test1($str);
// will output an error message saying argument $str is undefined in test1().
$obj->test1();
// will output ----> An object is just a copy of the class.
// will output -----> Ford, F-150, Grey
$obj->test2();
// will output an error message saying test2() requires at least one argument.
$obj->test2($str);
// will output -----> An object is just a copy of the class.
In the above example, we create an object using keyword new. But an object can be created using a type hint as well.
You will often see objects being created using a type hint in a lot of code, particularly in other languages like
Java, C/C++, Delphi, Python, etc. A type hint is a class that derives an object that following it -- it is a
hint about what an object of which class.
In PHP, we can have type hint as well, for example:
class Foo
{
public $bar; // $bar is a property that will hold a type hint object
public $zar; // $zar is a property that will hold a type hint object
As you can see in the constructor below, it has a 'type hint' called Bar and Zar, which create
objects called $bar and $zar, respectively.
// notice the 'type hints' which indicate that $bar and $zar are ojects of Bar and Zar, respectively
public function __construct(Bar $bar, Zar $zar)
{
// constructor body
$this->bar = $bar; // now $this->bar holds an object created by a 'type hint'
$this->zar = $zar; // now $this->zar holds an object created by a 'type hint'
}
}
Now you can do anything with the objects: $this->bar and $this->zar anywhere within this class Foo.
Here are some more examples that show 'type hint':
public function __construct(TaxManager $tax)
As you can see in the constructor, it has a 'type hint' called TaxManager, which is a class, and also,
it has an object called $tax.
So $tax is just a copy or a clone or an instance of the class TaxManager.
Suppose that class TaxManager has a property called $taxRate and a method called calculateTax(),
we can use the $tax object to refer to class TaxManager's member variables/properties and methods
like you normally would with an object created using 'new' keyword. for example:
public function __construct(TaxManager $tax)
{
$this->taxrate = $tax->taxRate; // here, we're using an object $tax to refer to $taxRate
$this->tax = $tax->calculateTax(); // here, we're using an object $tax to refer to calculateTax()
}
In the above example constructor code, be careful when passing arguments. You have to
pass it like this: Invoice(new TaxManager()), assuming Invoice is the class containing the constructor above.
// Here is an example as an array object:
class NeuralNetwork
{
private $input = array(); // input information
private $hidden_layer = array(); // layers in the network
public function __construct(array $input) // notice the 'type hint' which indicates $input is an array variable
{
// constructor body
}
}
In the case of array object, array(), it tells us that $input is of type array.
In Java, you'll often see a lot of objects created using type hints, for example:
As you can see in the following, HttpServletRequest is the class and request is the object
Likewise, HttpServletResponse is the class and response is the object
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException
{
doPost(request, response);
}
try
{
// As you can see MimeMessage is the class and message is the object
MimeMessage message = new MimeMessage(session);
}
catch (MessagingException mex) // Likewise, MessagingException is the class and mex is the object
{
mex.printStackTrace();
}
A class is the program you write (i.e., the MyClass class implementation above); while object (i.e., $obj) is the copy of the class or the clone of the class, most often being known as the instance of the class (MyClass, in this case).
A class resides in ROM (a permanent memory area: Read Only Memory), whereas object (i.e., $obj) resides in RAM (a temporary memory area: Random Access Memory.)
In ROM, data is stored there permanently even when the computer is turned off. In a RAM memory area, on the other hand, data get stored temporarily while the program is running or while the computer is still turned on. When the computer is turned off, the RAM data (i.e., $obj) is completely erased and is no longer stored in the RAM.
Instances of a class can be useful only while the program is running or while the computer is turned on; and when the program is not running or when the computer is turned off, instances of a class are no longer useful to a program; and therefore, it is stored in a temporary memory area.
Instances of a class can be created 'on the fly' at any time when needed by a program [as you can see above: $obj = new MyClass()].
Instances of a class are often being created from everywhere when needed (i.e., libraries, frameworks, and other classes, etc.)
So there is no need to store instances of a class permanently in permanent memory spaces and wasting valuable memory spaces.
to create an object, use the keyword new in the front of a class
objects can be created using 'type hint' as well
the keyword new means to create an instance of a class -- or to create a copy or a clone of a class
an 'object' is just a copy or a clone or an instance of a class!
a class has three types of attributes!
1st attribute of the class:
the purpose of the 1st attribute of the class is to store content value that is
constant and can't change its value during the lifecycle of the application
2nd attribute of the class:
the purpose of the 2nd attribute of the class is to store content value that is
constantly changing its value during the lifecycle of the application.
3rd attribute of the class:
the purpose of the 3rd attribute of the class is to calculate and manipulate the
content values that contain in the 1st and 2nd attribute property variables.
Note:
In programming, a class mimmicking a real world object, in which, it has attributes
just like a real world object has. For example, say, a real world human has two arms,
two legs, a name, address, email, phone, username, password, a face, hair, and other
body parts.
All those are called attributes -- attributes are some entities that enable the "body"
or "object" (or a human in this case) to function properly. "Attribute" means to "help."
All those attributes are called properties in programming and also usually known as
variables. Variables are just a term used to hold values in programming (or in computer memory).
They are placeholders to hold values in the computer memory so that they can be stored
and retrieved.
So when people say attributes, properties, and variables, they mean those three having the
same meaning and they are being used interchangibly.
For example, I use: 1st and 2nd 'attribute' 'property' 'variable' in my description throughout
this tutorial -- all in one phrase: 'attribute property variable' to emphasize the meaning of
the placeholder in computer memory, which is an attribute or a property or a variable.
All three have the same meaning and can be used interchangibly -- most often being used as one
phrase (as you'd seen throughout my description).
I found that beginning programmers are often confused with the word 'property' when they see one.
Just know that in programming, we often use the word property a lot to mean variable.
And also in programming, we often use the word attribute a lot to mean variable or function
(also known as method).
The three have the same meaning and can be used interchangibly -- and often as one phrase.
As you can see, a class has three attributes: 1st is the constants, 2nd is the variables, 3rd is
the functions (also known as methods).
In the dictionary the word 'attribute' means a quality or feature or property
regarded as a characteristic or inherent part of someone or something. Verb: to help!
In computer programming the word 'attribute' means a piece of information which
determines the properties of a field or tag in a database or a string of
characters in a display.
A true definition of a class is an object-oriented model mimicking how real objects behave. For example, a class called Car would have the usual three attributes: the engine (implemented as const COMBUSTIBLE_ENGINE = 'v8-engine'; (2nd attribute implemented as properties) the make, model, color; and (3rd attribute) at a minimum it must contains the constructor function to initialize the objects and the ignition (implemented as a method called Ignition()) to start the car.
That is object-oriented class. So when you think of a class, think of it as a real world object that exists in the real world. That's what a class is -- a real world object that you can observe.
An object-oriented class is a class that mimicks or behaves like a real world object.
You may have heard people mentioned the term object-oriented programming when talking about building applications or when talking about programming methodologies in general.
They are really talking about classes. Classes are object-oriented methodology.
In the old days (the 1960s, 1970s and up to the first half of the decade of 1980s), there were no object-oriented programming methodologies available. There were no classes available. So programmers had to program the hard way using only variables, methods, functions, and procedures to do their programming work.
That was during the early days of the technology revolution and the Web hadn't even been invented yet. So you couldn't program anything sophisticated up to the first half of the decade of the 1980s because object-oriented programming hadn't been invented yet (or more specifically, classes or the concept of classes hadn't been invented yet).
During the second half of the decade of the 1980s and onward, object-oriented programming was developed and enabled very sophisticated applications to be developed to this day. Classes were the foundation of the technological revolution. Without classes we wouldn't have been able to program very sophisticated applications.
Today, if you hear people talk about object-oriented programming, just ask them: What is a non-object-oriented programming? (To see if they know one exists.)
There are none!!!
All of today's programming are object-oriented programming. So the term object-oriented programming is obsolete and it has been obsolete since the start of the millenial decade (2000s). It is irrelevant nowaday and onward.
So keep this in mind: All classes are object-oriented programming methodology. Classes mimick how real world objects behave. Classes are the foundation of the programming world.
When you approach to building (or creating a class), you first think of the real world object that class represents (i.e., a car, a person, a customer, an employee, a student, etc.) and then you proceed to creating that class by using the three attributes to represent the real world object that forms the class that you're creating.
For example, if you want to program an application about a person, whether that person is a student, a teacher, a co-worker, a doctor, a lawyer, a customer, or an employee of a company, etc, you would think in term of real world about that person, which is, that person has a name, an address, a phone, email, a username, a password, etc.
By the way, a person is a very generic term and it can be applied to other uses as well; for example, it can be applied to a customer, a student, a teacher, a co-worker, a doctor, a lawyer, a customer, or an employee of a company, etc.
Question: How would you create a class for that person? Or for any person? Or for a generic uses of/for that person?
The answer to that question can be varied depending on what type of application you're building, but all cases require you to think of the real world object implementing the three attributes that form the foundation of the class.
For example, if you're building an application to store a person's personal profile, you would start with a person and list the attributes of that person. For example, a person has a name, address, phone, email, username, password, etc.
Next, ask yourself a question: which of the items belong to the 1st attribute of the class? Which belong to the 2nd attribute of the class? Which belong to the 3rd attribute of the class? And finally, which belong to none of the above?
Well, by looking at the list, we can see clearly that 'address' stands out among them, because 'address' has attributes of its own: street number, apt #, suite #, city, state, zip, country, etc.
This means that 'address' is just like 'person' and they both have attributes of their own. So both 'person' and 'address' are classes. None of the rest in the list have attributes, so they are either belonging to the 1st or 2nd attribute of the class.
Knowing that, we can go ahead and create two classes called Address and Person to record that person's profile information.
Now since class Person has an attribute called address and address has attributes of its own, we can say that address is a supporting class of Person. In other words, class Person needs class Address to make class Person more suiteable to record a person's profile because in the real world a person needs an address to live in.
Now let's build those classes: Address and Person:
<?php
/**
* this class is a model class in an MVC scheme of thing
* see my other tutorial about MVC called Advanced Pattern Programming: MVC
* notice that the namespace points to the folder names called 'path', 'to', 'model'
* you can rename them accordingly!
* 'path', 'to', and 'model' are actually folder names containing the models or classes
* if you desire to have more levels of folders, you can add them accordingly,
* for example: namespace path\to\my\resource\model;
* of course, you need to autoload them accordingly as well, or else
* it won't work!
* see my other tutorial called 'How to autoload classes using SPL'
* or you can use class level loading and remove the namespace and the use clauses
* and it will work just fine!
* just put the include statement(s) at the top of every class that uses the file!
*
* as you can see in the namespace, you can put all of your model in a folder called 'model',
* including this class Address
*/
// 'path', 'to', and 'model' are actually folder names containing the models or classes
namespace path\to\model;
class Address
{
// 1st attribute of the class Address:
// the purpose of the 1st attribute of the class is to store constant value.
// declaring class constant variables
// for class Address there are no constant variables
// you may find a use of the constant for Address, however!
// 2nd attribute of the class Address:
// the purpose of the 2nd attribute of the class is to store property
// variable values that are constantly changing during the lifecycle
// of the application.
// the 2nd property variables must be declared prefacing with visibility control.
// public, protected, private are visibility control.
// notice that class Address has an attribute called name
// well, if you think in the real world term, an address is for somebody to live
// in or an address is an object that can accomodate other objects: a person or a name
// in this case, an address has a name of a person tied to it as its attribute
// in programming an application, we need to associate a name of a person to
// the object called Address so that we can relate them to one another
public $name;
public $street1;
public $street2;
public $city;
public $state;
public $zip;
public $country;
// 3rd attribute of the class (Address):
// the purpose of the 3rd attribute of the class is to calculate
// and manipulate the values of the 1st and 2nd attributes of the class.
// 3rd attribute methods must be declared prefacing with visibility control
// public, protected, private are visibility control.
// for the 3rd attribute in the example below, most of the tasks are being done
// to validate the address's 2nd attributes so that they all are
// valid attributes.
// that is all that need to be done for the class Address
// very simple and can be utilized by others like: customer, student, employee, etc.
public function isNameValid()
{
// this function will return the full name of the person
// if you desire to seperate the first/last name of the person
// you can do so accordingly very easily!
return strlen($this->name) > 0;
}
public function isStreet1Valid()
{
// this function will return the street address1 of the person
// notice that there is no need to validate street address2
// because street address2 is optional and generally for apt, suite, etc.
return strlen($this->street1) > 0;
}
public function isCityValid()
{
// this function will return the city address of the person
return strlen($this->city) > 0;
}
public function isStateValid()
{
// this function will return the state of resident of the person
return strlen($this->state) == 2;
}
public function isZipValid()
{
return strlen($this->zip) == 5;
}
public function isCountryValid()
{
return strlen($this->country) > 0;
}
// this function is being called by class Person's validate() method and it looks like this:
// return $this->billingAddress->validate();
// with billingAddress being an instance of class Address
// and it is very very elegance!!!
// to see an even more elegance(ness) at work, please see class Main later!
public function validate()
{
// this function will return the valid name of the person
return $this->isNameValid();
}
}
?>
Remember that, an address is a supporting class of Person. In other words, class Person needs class Address to make class Person more suiteable to record a person's profile.
Okay, let's create a person class to record that person's profile information. For example:
<?php
/**
* this class is a model class in an MVC scheme of thing
* see my other tutorial about MVC called Advanced Pattern Programming: MVC
* notice that the namespace points to the folder names called 'path', 'to', 'model'
* you can rename them accordingly!
* 'path', 'to', and 'model' are actually folder names containing the models or classes
* if you desire to have more levels of folders, you can add them accordingly,
* for example: namespace path\to\my\resource\model;
* of course, you need to autoload them accordingly as well, or else
* it won't work!
* see my other tutorial called 'How to autoload classes using SPL'
* or you can use class level loading and remove the namespace and the use clauses
* and it will work just fine!
* just put the include statement(s) at the top of every class that uses the file!
*
* notice that the use clause references the folders: 'path', 'to', 'model' as well as
* the class name called 'Address'
* this is needed!
* now class Person has access to class Address in full capability as if you had
* used the class level loading method!
* either method will work just fine, but namespace and application level loading is
* more robust and efficient!
*
* as you can see in the namespace, you can put all of your model in a folder called 'model',
* including this class Person and the previous class Address
*/
// 'path', 'to', and 'model' are actually folder names containing the models or classes
namespace path\to\model;
use path\to\model\Address;
/**
* this class is very generic and it can be changed to other uses as well,
* for example, you can rename it to Customer, Student, Employee, etc.
*/
class Person
{
/**
* 1st attribute of the class (Person):
* declaring class constant variables
* for class Person there are no constant variables
* you may find a use of the constant for Person, however!
*
* 2nd attribute of the class (Person):
* class properties: properties must be declared prefacing with visibility control
* public, protected, private are visibility control:
*
* if you remember the list, a person has an address and that address has already
* been taken care of earlier in a class called Address
*
* now we need to glance over the list again and we can see that it has email, phone,
* social security, username, password, etc.
*
* so we need to implement those as the 2nd attributes
*
* in case you're doing an ecommerce shopping site, you can use this
* property variable called $billingAddress to direct your application to
* the billing address during the check out process
*
* yes, these classes/applications/codes are very generic and you can customize
*them to suit your objectives!
*/
public $billingAddress;
public $email;
public $phone;
public $social_security_number;
/**
* 3rd attribute of the class (Person):
* class methods: methods must be declared prefacing with visibility control
* public, protected, private are visibility control:
*
* for the third attributes, we start with a constructor to initialize the class
* Address
* more specifically, we need to create an instance of the class Address and
* store it in the 2nd attribute variable called billingAddress
* the rest of the 3rd attributes are just methods to validate the 2nd attributes
* if you have other ideas for other 3rd attributes to accomplish something, like
* looking up in a database to retrieve something, you can add them here in
* the 3rd attribute section
*/
public function __construct()
{
// this constructor function will assign an instance of the address of the
// person to the 2nd attribute property variable called 'billingAddress'
// this way, you can access the person's address info from other
// classes that make use of this person address info!
$this->billingAddress = new Address();
}
public function getName()
{
// this function will return the valid full name of the person
return $this->billingAddress->name;
}
public function validateSocialSecurityNumber($social_security_number)
{
// this function will return the valid social security number of the person
// you might want to do a better job in validating social security number than this
return preg_match('/^[0-9]{3}-[0-9]{2}-[0-9]{4}$/', $social_security_number);
}
public function isSocialSecurityNumberValid($social_security_number)
{
// this function will return the valid social security number of the person
return $this->validateSocialSecurityNumber($social_security_number);
}
public function validateEmail($emailToValidate)
{
// this function will return the valid email of the person
// check if email address is well-formed using PHP's built-in filter_var()
// Google the Web for a more robust email validation function
return filter_var($emailToValidate, FILTER_VALIDATE_EMAIL);
}
public function isEmailValid()
{
// this function will return the valid email address of the person
return $this->validateEmail($this->email);
}
public function validatePhone($phone)
{
// this function will return the valid phone of the person
return preg_match('/^[0-9]{3}$/', $phone);
}
public function isPhoneValid()
{
return $this->validatePhone($this->$phone);
}
public function validate()
{
// this function will return the valid billing address of the person
// notice that this call is to the class Address's validate()
return $this->billingAddress->validate();
}
}
?>
Now we got two classes supporting each other: Person and Address.
So let's build a service application that makes use of the two classes to store a person's personal profile. For example:
<?php
/**
* notice that the namespace points to the folder names called 'path', 'to', 'model'
* 'path', 'to', and 'model' are actually folder names containing the models or classes
* you can rename them accordingly! this class assumes to reside in 'path/to/model' folder!
* if you desire to have more levels of folders, you can add them accordingly,
* for example: namespace path\to\my\resource\model;
* of course, you need to autoload them accordingly as well, or else
* it won't work!
* see my other tutorial called 'How to autoload classes using SPL'
* or you can use class level loading and remove the namespace and the use clause
* and it will work just fine!
* just put the include statement(s) at the top of every class that uses the file!
*
* as you can see in the namespace, you can put all of your model in a folder called 'model',
* including this class Application and the previous classes: Address, Person, and any other
* model classes that you might have
*/
// 'path', 'to', and 'model' are actually folder names containing the models or classes
namespace path\to\model;
/**
* notice that the use clause references the folders: 'path', 'to', 'model'
* as well as the class names called 'Address' and 'Person'
* this is needed!
* now class Person has access to class Address in full capability as if you had
* used the class level loading method!
* either method will work just fine, but namespace and application level loading is
* more robust and efficient!
*/
use path\to\model\Address;
use path\to\model\Person;
/**
* this class will make use of the other classes: Address, Person
* this class is a model class in an MVC scheme of thing
* see my other tutorial about MVC called Advanced Pattern Programming: MVC
*/
class Application
{
// 1st attribute of the class (Application):
// declaring class constant variables
// for class Application there are no constant variables
// you may find a use of the constant for Application, however!
// 2nd attribute of the class (Application):
class properties: properties must be declared prefacing with visibility control
public, protected, private are visibility control:
public $person;
public $workAddress;
public $foreignAddress;
// in case you order items online and bill it to a different address, i.e., your employer
// yes, I've seen strange things people do!
public $billingAddress;
// in case you order items online and has a different address to ship, i.e., your landloard
// yes, I've seen strange things people do with their shipment!
public $shippingAddress;
// of course, you can have lots more 2nd attributes here!
// 3rd attribute of the class (Application):
class methods: methods must be declared prefacing with visibility control
public, protected, private are visibility control:
public function __construct()
{
// this constructor function will assign an instance of the address of the person to the
// 2nd attribute property variable called 'shippingAddress' (among other assignments)
// this way, you can access the person's address info from other
// classes that make use of this person address info!
// also this is in case you need to have your packages ship to a different location!
$this->billingAddress = new Address();
$this->shippingAddress = new Address();
$this->workAddress = new Address();
$this->foreignAddress = new Address();
$this->person = new Person();
}
public function validate()
{
// this function will return true or false depending on whether a person
// info has been validated or not!
// notice the call to $this->person->validate() is actually calling
// class Person's method called validate()
//
// just follow this elegant code flow and you'll be fine!
return $this->person->validate();
}
// of course, you can have more functions to do other things as well!
}
?>
At this point, all of the models have been created and from here and on, you can create external controller classes to make use of the models: Address, Person, and Application.
Remember that, controller (specifically external controller) dictate or delegate, organize the tasks. It is akin to office managers dictating and delegating the tasks to their employees. Employees do all the work and managers do very little work and only organize, dictate, and delegate the tasks.
Now what's left is to create an instance of the class Application and use it accordingly. For example:
<?php
/**
* this class is a controller class in an MVC scheme of thing
* see my other tutorial about MVC called Advanced Pattern Programming: MVC
*
* if you remember that a controller class in an MVC scheme of thing does very
* little work. however, in this class, I broke that rule by doing a lot work in
* here like grabbing all the POST variables and store them in the 2nd attributes
* of the model classes
*
* well, sometimes I break my own rule because of my laziness instead of doing all of the
* handling of the POST tasks in the actual "external" controller and not in the base controller!
*
* just to be clear: nothing stops you from doing what I'm doing here!
* however, the downsize is that you are setting up yourself to repeat this habbit
* over and over and over again and that's will make you a bad programmer!
* and one of these days your code will contain bugs!!!
*
* to be proper, this class should do very little of coding, and that is, it should
* just create an instance of the model and ask the model if the POST variables that
* are sent by the user are valid: true or false!
*
* or in most cases, in the model, there should be method(s) that handle the POST
* items accordingly and insert them into the database!
*
* that method that handles/inserts POST items into the database should return true when
* the items are inserted into the database successfully, and false otherwise!
*
* again here, due to my laziness, I bypassed all that tasks completely and only to
* implement this as a base controller class to give you somewhat a guideline for you
* to complete the tasks (yourself) of building a functional application.
*
* actually, this class is a "main" controller base class in an MVC scheme of thing,
* similar to classes Base in "Advanced Programming: MVC" and class Example in my other
* tutorial called 'How to autoload classes using SPL'
*
* so in actuality, I did not provide "external" controller classes for this example and
* only leave them for you to implement your own as well as your own view, too!
* this ends the topic about MVC rant!
*
*
* notice that the namespace points to the folder names called 'path', 'to', 'controller'
* you can rename them accordingly! this class assumes to reside in 'path/to/controller' folders!
* if you desire to have more levels of folders, you can add them accordingly,
* for example: namespace path\to\my\resource\controller;
*
* of course, you need to autoload them accordingly as well, or else
* it won't work!
* see my other tutorial called 'How to autoload classes using SPL'
* or you can use class level loading and remove the namespace and the use clause
* and it will work just fine!
* just put the include statement(s) at the top of every class that uses the file!
*
* as you can see below, you can put all of your controller in a folder called 'controller'
*/
namespace path\to\controller;
/**
* notice that the use clause references the folders: 'path', 'to', 'model'
* as well as the class name called 'Application'
* this is needed!
* now class Main has access to class Application in full capability as if you had
* used the class level loading method!
* either method will work just fine, but namespace and application level loading is
* more robust and efficient!
*/
use path\to\model\Application;
/**
* this class will make use of the class Application
*/
class Main
{
// 1st attribute of the class (Main):
// declaring class constant variables
// for class Main there are no constant variables
// you may find a use of the constant for Main, however!
// 2nd attribute of the class (Main):
class properties: properties must be declared prefacing with visibility control
public, protected, private are visibility control:
public $app;
// of course, you can have lots more 2nd attributes here!
// 3rd attribute of the class (Main):
class methods: methods must be declared prefacing with visibility control
public, protected, private are visibility control:
public function __construct()
{
// this constructor function will assign an instance of the address of the
// person to the 2nd attribute property variable called 'shippingAddress'
// this way, you can access the person's address info from other
// classes that make use of this person address info!
// also for in case you need to have your packages ship to a different location!
$this->app = new Application();
// all of these are just assigning the POST items sent by the form and put them
// into their proper variables! nothing special!
// this happens whenever a user fills out a form and press 'submit' button and
// they all will come here and you can grab those items and use them here and
// anywhere else for that matter!
// you can insert these POST items into the database as well!
// notice that, you can set this property called 'app' so that the view can
// use them. see "Advanced Pattern Programming: MVC" where I show a set()
// and a get() for the purpose of setting all these properties in class Base()
// so assuming if you have an "external" controller to handle these POST,
// you would do like this in that "external" controller:
// $app = new Application();
// $base = new Main(); // or Base() in the MVC example!
// $base->set('app', $app->person->billingddress);
// remember that in PHP, you can use properties on the "fly" without
// having to declare them first!
// in here, we set the undeclared property called 'app' and class Base will happily
// accepts 'app' as its own property! awesome!
// now in the view, you can retrieve that property by doing this:
// $main = new Main();
// $app = $main->get('app');
// you can display these values to your users or do whatever with them!
// foreach ($app as $value)
// {
// $name = $value->name; // $name = 'John Doe'
// $street1 = $value->street1; // $street1 = '123 Main St'
// $city = $value->city; // $city = 'Minneapolis'
// }
$this->app->person->billingddress->name = $_POST ['name'];
$this->app->person->billingddress->street1 = $_POST ['street1'];
$this->app->person->billingddress->street2 = $_POST ['street2'];
$this->app->person->billingddress->city = $_POST ['city'];
$this->app->person->billingddress->state = $_POST ['state'];
$this->app->person->billingddress->zip = $_POST ['zip'];
$this->app->person->billingddress->country = $_POST ['country'];
$this->app->person->billingddress->email = $_POST ['email'];
$this->app->person->billingddress->phone = $_POST ['phone'];
// you can do the same thing for other addresses, i.e., shippingAddress
// of course, you have to grab from the proper form values sent by your users
// here, we assume that the shipping and billing address are the same!
$this->app->person->shippingAddress->name = $_POST ['name'];
$this->app->person->shippingAddress->street1 = $_POST ['street1'];
$this->app->person->shippingAddress->street2 = $_POST ['street2'];
$this->app->person->shippingAddress->city = $_POST ['city'];
$this->app->person->shippingAddress->state = $_POST ['state'];
$this->app->person->shippingAddress->zip = $_POST ['zip'];
$this->app->person->shippingAddress->country = $_POST ['country'];
$this->app->person->shippingAddress->email = $_POST ['email'];
$this->app->person->shippingAddress->phone = $_POST ['phone'];
}
// of course, you have some functions to do other things as well!
}
?>
Okay, you've seen how you approach in building an application large or small by laying out a road map by thinking that a class mimicks a real world object and using the guideline shown in this tutorial should help you build any application large or small in an elegance way.
There you have it!
And have fun building applications!
A very simple and short answer is: A constructor is just an empty or blank function.
That is it! A hollowed empty function that contains nothing! That's what a constructor is. It's an empty or blank function that contains nothing.
A constructor __construct() is often known as a magic method because PHP does its magic behind the scene by calling it or invoking it magically behind the scene whenever you create an instance of its class.
There are many magic methods in PHP and the following method names are considered magical: __get(), __set(), __isset(), __unset(), __construct(), __destruct(), __call(), __callStatic(), __sleep(), __wakeup(), __serialize(), __unserialize(), __toString(), __invoke(), __set_state(), __clone(), and __debugInfo().
Notice that they all use the __ (double underscores), including __construct().
Notice also that all these magic methods are magically called by PHP automatically. For more, please see my other tutorial called Magic Methods: __set(), __get(), __isset(), __unset()
Earlier, we talked about the definition of a class. Now we're talking about the definition of a constructor, which is just an empty function.
That empty(ness) is by design to allow programmers to put some code in it.
Remember that a class has three attributes: 1st, 2nd, and 3rd attributes.
The 3rd attribute contains one of the most important attribute of the class concept, and that attribute is called a constructor.
What is so significant about a constructor?
A constructor is very significant, in that, it gets called every time its class gets referenced.
I repeat: A constructor gets called every time its class gets referenced.
The keyword is referenced -- meaning, called or instantiated. For example, $obj = new MyClass().
As you can see, MyClass gets referenced and if it has a constructor, its constructor will get called or executed automatically.
This is very significant because it gets called automatically without you having to explicitly call it as you normally would with other 3rd attributes.
So you can say that a constructor is an empty special 3rd attribute of the class. No one else in the 3rd attribute category that has any special preferential treatment like a constructor does.
With this priviledge (and empty-ness), you can put all kinds of code in the constructor to be executed automatically whenever its class is referenced. Very neat!!!
Typically, the kinds of code you put in the constructor are code that needed to be instantiated or initialized. You've seen in class Person, its constructor contains a line of code that instantiating an address class: $this->address = new Address().
You don't do a lot of heavy duty programming like querying a database inside a constructor. You leave all of the heavy duty jobs to other 3rd attributes. The purpose of a constructor is just to do simple and quick instantiations and initializations of the code. Nothing else!
Note: The variable $this refers to the current class (or object) which is class Person (in the case of $this->address = new Address()).
A class does not require a constructor if the class doesn't need to instantiate or initialize other objects or code. In other words, if you don't need your code to be executed automatically every time your class is referenced, then you don't need a constructor for your class.
When creating a class, you have to decide whether your class needs a constructor or not depending on whether your class needs to instantiate or initialize any objects (or code) at all.
Another point of note is that, you have to decide whether or not some of the code inside your class need to get executed automatically whenever your class gets referenced. Anything inside a constructor will get executed automatically whenever its class is referenced.
In summary, the purpose of the constructor is to get code executed automatically every time its class gets referenced. That's all a constructor does and nothing else. If you don't have code that needs to be executed automatically every time your class gets referenced, then you don't need a constructor for your class.
In the following example, function Connect() gets executed automatically whenever class Connection gets referenced, even though function Connect() is outside of the constructor, because a code inside the constructor calls it.
This is how you make your non-constructor functions get called automatically whenever their class gets referenced. For example:
<?php
/**
* as you can see in the namespace, you can put all of your model in a folder called 'model'
*/
namespace path\to\model;
class Connection
{
// 2nd attribute of the class (Connection):
private $username;
private $password;
private $db_name;
private $host;
private $isConnect;
// 3rd attribute of the class (Connection):
public function __construct($user, $pass, $dbName, $url)
{
// initialize the variables username, password, host, db_name, with the
// argument values sent in via the contructor heading: user, pass, dbName, url
// notice that variable $this refers to the current object: $obj = new MyClass()
$this->username = $user;
$this->password = $pass;
$this->db_name = $dbName;
$this->host = $url;
$this->isConnect = $this->Connect();
}
public function Connect()
{
// notice that this function gets called automatically whenever class Connection
// gets referenced because this function gets included in the constructor above!
// this function returns the PDO connection object
return new PDO("mysql:host=$this->host;dbname=$this->db_name", $this->$username, $this->$password);
}
} // end class Connection
/**
* Usage:
*
* $pdo = new Connection('my_username_123', 'my_password_123', 'my_database_name_123', 'my_db_server_123');
*
* The above creation of an instance of class Connection causes the class Connection to get
* referenced, and as a result of this referenced, its constructor gets called automatically!
* Now you can use the instance of class Connection as you normally would:
*
* if ($pdo) // we could do this as well: if ($pdo->Connect)
* {
* // it is connected
* $sql = 'SELECT * FROM myTable';
* $query = $pdo->prepare($sql);
* $resource = $query->execute();
* $result = $resource->fetch(PDO::FETCH_ASSOC);
*
* // now you can do whatever with the associative array variable $result
*
* while ($row = $result->fetch())
* {
* // well, I'm just pretending that 'myTable' contains only a username and password
*
* $username = $row['username'];
* $password = $row['password'];
* }
*
* }
*/
?>
As stated earlier, a constructor is automatically called whenever its class gets referenced. This means that we do not need to call a constructor directly and manually by hand -- it is automatically called by the programming compiler behind the scene whenever its class gets referenced. The keyword here is referenced.
To refer (or reference) a class, you create an instance of a class. For example:
<?php
/**
* as you can see in the following, we refer to classes Address and Person by creating instances of the
* classes using keyword new
*
* now since class Address doesn't have a constructor, the reference didn't trigger a call to the constructor
*
* on the other hand, a reference to classes Person and Connection will trigger a call to its respective
* constructor because both classes Person and Connection have their own constructor
*/
$this->foreignAddress = new Address();
$this->person = new Person();
$pdo = new Connection('my_username_123', 'my_password_123', 'my_database_name_123', 'my_db_server_123');
?>
Since the purpose of a constructor is to allow you to put some code in it to be executed automatically by the compiler, you can pass outside values as parameters of the class to its constructor to be executed automatically, and thus allow you to use those outside values to initialize variables/properties of the class inside a constructor.
As you can see from the previous example in class Connection, it passes outside values to the constructor to be used as connection parameters. For example, class Connection has four parameters to be passed in via its constructor:
<?php
public function __construct($user, $pass, $dbName, $url)
?>
And then we can pass outside values to class Connection via its constructor like the following.
Notice that you pass outside values to the class through its constructor. This means that the outside values you pass to the class must match the number of parameters contain in the constructor.
In this case, we pass four outside values: 'my_username_123', 'my_password_123', 'my_database_name_123', 'my_db_server_123' to correspond with the constructor parameters $user, $pass, $dbName, $url, respectively.
<?php
$pdo = new Connection('my_username_123', 'my_password_123', 'my_database_name_123', 'my_db_server_123');
?>
Now class Connection has full control of the outside values at its disposable. It can do whatever it wants with these outside values inside class Connection.
That is how you pass outside values to a class to be calculated and manipulated in a class.
Remember that the purpose of the 3rd attribute (including the constructor) of a class is to calculate and manipulate values of the 1st and 2nd attributes of the class?
These outside values get assigned to the 2nd attribute of a class inside the constructor. The constructor is also a member of the 3rd attribute of a class.
Earlier I mentioned that if you have some code that need to be executed automatically whenever its class gets referenced, you need to put them in the constructor. However, the constructor is not the only "game in town" that you can put your code to be executed automatically whenever its class gets referenced -- there is another "game in town" that can accomplish this very same thing. You can use a neat trick to accomplish the same thing a constructor does. Here is how.
<?php
/**
* Illustrating a neat trick to mimick a constructor
*/
namespace path\to\model;
class MyClass
{
// 2nd attribute of the class (MyClass):
public $make;
public $model;
public $color;
// 3rd attribute of the class (MyClass):
public function __construct($make = null, $model = null, $color = null)
{
// initialize variables $make, $model, $color
// notice that variable $this refers to the current object: $obj = new MyClass()
$this->make = $make;
$this->model = $model;
$this->color = $color;
}
public function init()
{
// notice that this function gets called automatically whenever class MyClass
// gets referenced because this function gets included at the bottom of this class!
// see the call to this function at the bottom of this class
// you can do whatever you desire inside this init(), such as code initializations
// $address = new Address();
// but here, we'll just return null for this illustration!
return null;
}
} // end class MyClass
// Notice that this call is outside of class MyClass but inside the file MyClass.php
// In fact, in here, you can call as many functions/methods as you want to mimick a constructor.
$obj = new MyClass();
$obj->init();
/** THIS IS THE END OF FILE: MyClass.php **/
/**
* Usage:
*
* $obj = new MyClass('Toyota', 'Camry', 'blue');
*
* The above creation of an instance of class MyClass causes the class MyClass to get
* referenced, and as a result of this referenced, its method init() also gets called automatically!
* Now you can use the instance of class MyClass as you normally would.
*
* Notice that every time this class (MyClass) gets referenced, it runs all the way down to
* the bottom of the file, and in effect, it executes the line that calls init()
*
* As you can see, this is a very neat trick to mimick a constructor in case your
* constructor is to bulky or congested to put more code in it.
*
* Using this trick will make your constructor very lean, especially if you have lots and lots
* of code to initialize.
*/
?>
Now that you know a lot about classes and its constructors, let's see some example uses so that you can build upon the knowledge you'd learned thus far.
Remember that classes Address and Person are very generic which means that you can customize them and use them for other purpose as well.
Suppose that you're building an ecommerce application, the first question you ask yourself is: What is an ecommerce?
Well, everybody knows that an ecommerce is a place or platform that allows people to buy and sell things.
Okay, the next question you ask yourself is: What sort of things involved in an ecommerce transaction; in other words, what do you need in a shop or online shop if you're going to allow shoppers to be able to shop at a store or at an online shopping site? What do you need?
To answer that question, you follow the same process shown earlier with the classes Address and Person and think of the real world scenario and apply it to your starting point.
This means that an ecommerce involves a person, also known as a customer. So immediately we can say that we need a 'Customer' class but we already have a generic class called 'Person' that we can use to customize it to suite our purpose. So just change the already created 'Person' class into a 'Customer' class and we're all set to go.
Next, a customer has an address, email, phone, username, password, etc. Again, we already have a generic class called 'Address' and so we're all set to go.
Next, a customer (or an ecommerce) has to have a cart for customers to use. In other words, a 'Customer' class will interact with a 'Cart' class.
So the next question is: What is a cart?
Well, a cart is for putting items in it.
Now clearly from the description above a cart has an attribute called 'item'.
The next question is: What is an item?
Well, an item has a name, description, the shape and size, color, a picture (a url), etc., to identify itself.
So clearly we know that a cart has attributes (just item for now) and an item also has attributes. So we will need to create a class called 'Cart' and as well as a class called 'Item'. [Remember that we already have a generic class called 'Person' that we can use to customize it into a 'Customer' class.]
The next question is: Are there anymore attributes for a cart or for an item?
Yes, there are for both. For the cart, a shopper can add and remove items to and from the cart. So clearly right now we know that a cart has at least three attributes: Item, addItem(), removeItem().
There maybe more, such as to calculate the total price, to count the items, to apply discount and promo, to calculate the weight, etc.
For now, we follow the same process outlined earlier with the classes: Address and Person.
For example, class Cart has these attributes: Item, addItem(), removeItem().
By looking at the list, we can see clearly that Item stands out among the three attributes. Item has its own attributes: id, price, description, color, size, shape, make, model, url, image, etc.
This means that Cart and Item are classes, with Item acts as a supporting class of class Cart.
Now let's create these classes called 'Item' and 'Cart'. For example:
<?php
/**
* this class is a model class in an MVC scheme of thing
* see my other tutorial about MVC called Advanced Pattern Programming: MVC
* as you can see in the namespace, you can put all of your model in a folder called 'model'
*/
namespace path\to\model;
class Item
{
/**
* 2nd attribute of the class (Item):
*
* remember that the purpose of the 2nd attribute of the class is to store
* property values that are constantly changing during the lifecycle of the application.
*
* this class is a model class in an MVC scheme of thing
* see my other tutorial about MVC called Advanced Pattern Programming: MVC
* as you can see in the namespace, you can put all of your model in a folder called 'model'
*
* again, using real world scenario, what sort of attributes an item has?
*
* clearly, an item has an id to identify itself whether it is an apple or an orange!
* it has a quantiy to tell how many a customer buys!
* next, price for each item!
*
* you can add some more attributes like product name, description, url, image, etc.
*
* the other two: discount and product are just extra things that you can add on
* to make your item relate to the customer in a shopping cart!
*/
public $id;
public $qty = 0;
public $price;
public $discount = 0;
// we could just as well name this attribute as 'catalog' which is more appropriate
// property variable $product holds products/items in the catalog
// it is an array of items in the catalog!
//
public $product = null;
/**
* 3rd attribute of the class (Item):
*
* remember that the purpose of the 3rd attribute of the class is to calculate
* and manipulate property values contain in the 1st and 2nd attributes.
*
* class Cart (below) references this class Item and in effect triggers a call to this
* constructor. for example:
*
* $this->item[$id] = new Item($qty, $product);
*
* argument $product being the catalog array of items!
*/
public function __construct($qty, $product)
{
// initialize the variables qty and product, with the
// argument values sent in via the contructor heading: $qty, $product
// notice that variable $this refers to the current object or current
// class 2nd attributes: qty, product
$this->qty = $qty;
$this->product = $prodcut;
}
public function getName()
{
// return the name of the product/item
return $this->product->name;
}
public function getPrice()
{
// return the price of the product/item
return $this->product->price;
}
public function getWeight()
{
// return the weight of the product/item
// notice that a product/item has many other attributes as well: size,
// make, model, color, etc.
// I'll leave all of that details for you to implement your own purpose!
return $this->product->weight;
}
public function getUrl()
{
// return the url of the product/item
// again, a product has to have a url to link to
return $this->product->url;
}
public function getQty()
{
// return the qty of the product/item
return $this->qty;
}
public function getProduct()
{
// return the actual product which was sent via the constructor
return $this->product;
}
public function extendedPrice()
{
// return the total price of the product/item minus discount
return ($this->qty * $this->getPrice * (1 - $this->discount);
}
public function discountedAmount()
{
// return the total discount amount of the product/item
return ($this->getPrice * $this->discount);
}
public function getDownload()
{
// this is just extra function to return a download material
// maybe not applicable or it may! remember that a product is vast!
return $this->product->download;
}
} // end class Item
/**
* Usage:
*
* $item = new Item($qty, $product);
* or $this->item[$id] = new Item($qty, $product);
*/
?>
Now that we got an Item class, we can just go ahead and build a 'Cart' class to put (or manipulate) that Item class. For example:
<?php
/**
* this class is a model class in an MVC scheme of thing
* see my other tutorial about MVC called Advanced Pattern Programming: MVC
* as you can see in the namespace, you can put all of your model in a folder called 'model'
*/
namespace path\to\model;
use path\to\model\Item;
class Cart
{
/**
* 2nd attribute of the class (Cart):
*
* remember that the purpose of the 2nd attribute of the class is to store
* property values that are constantly changing during the lifecycle of the application.
*
* remember that a shopping cart's purpose is to hold items and thoses items get
* added and removed constantly.
*
* so clearly we need an array to hold those items and this array variable will get
* used and manipulated constantly during the lifecycle of the application.
*/
public $item = array();
/**
* 3rd attribute of the class (Cart):
*
* remember that the purpose of the 3rd attribute of the class is to calculate
* and manipulate property values contain in the 1st and 2nd attributes.
*
* the bulk of building an application usually takes place in the 3rd attribute section of
* the class, and here, there are no exceptions -- we do all of the cart's calculation and
* manipulation tasks here in this 3rd attribute of the class (Cart).
*/
// I'm going to leave this constructor blank for you to fill in your own things!
// your application may need more features and you may need to use this constructor!
// this cart class is a generic barebone class that you can build upon it to make
// your ecommerce application more robust and powerful!
public function __construct()
{
// not implemented for this example! it's not needed for this example!
}
public function getNbLineItems()
{
// returns the number of items in the cart
return count($this->item);
}
public function getTotalWeight()
{
$totalWeight = 0;
foreach ($this->item as $id => $value)
{
$totalWeight = $totalWeight + ($value->qty * $value->getWeight());
}
// this function returns the total weight of all of the items in the cart
return $totalWeight;
}
public function getTotalItem()
{
$totalItem = 0;
foreach ($this->item as $id => $value)
{
$totalItem = $totalItem + $value->qty;
}
// this function returns the total number of all of the items in the cart
return $totalItem;
}
public function getTotalPrice()
{
$totalPrice = 0;
foreach ($this->item as $id => $value)
{
$totalPrice = $totalPrice + $value->extendedPrice();
}
// this function returns the total prices of all of the items in the cart
return $totalPrice;
}
public function setItemQty($id, $qty)
{
if ($qty == 0)
{
$this->removeItem($id);
}
else
{
$this->item[$id]->qty = $qty;
}
}
public function isEmpty()
{
// return true if the total number of all of the items in the cart = 0
// in other words, return true if no items in the cart
return ($this->getNbLineItem() == 0);
}
public function addItem($id, $qty, $product)
{
// if item exists, it is an old item, so simply update the qty to it
// else, it is a new item, so add this new item to the cart
if ($this->getItemQty($id) > 0)
{
$this->setItemQty($id, $qty);
}
else
{
$this->item[$id] = new Item($qty, $product);
}
}
public function removeItem($id)
{
// if there is an item (with this $id) in the cart, remove it
// remember that $this->item refers to all of the items in the cart
if (!$this->isEmpty())
{
$tmp = array();
foreach ($this->item as $idList => $value)
{
// if an item in the cart is not the item with this $id, then put it in $tmp
if ($idList != $id)
{
$tmp[$idList] = $value;
}
}
// store all of the items that are not the target of the deletion
// in other words, the deleted items are not stored in $this->item anymore!
$this->item = $tmp;
}
}
public function hasDiscount()
{
// iterating over all of the items in the cart to see if any item has a
// discount attached to it, then return true!
foreach ($this->item as $id => $value)
{
if ($value->discount > 0)
{
return true;
}
} // end foreach
return false;
}
public function removeAll()
{
// by initializing the variable $this->item to equal to an array() function,
// it erases the variable 'item' to equal to null! or equal to an empty array!
$this->item = array();
}
} // end class Cart
/**
* Usage:
*
* $cart = new Cart();
*
* $catalog is an array containing a catalog list of items for sale
*
* you pass in an id and a qty that you want to purchase available in the catalog
* that you pass in as well!
*
* this is mimicking a person looking at a catalog full of items for sale and choosing
* an item id and the qty to purchase.
*
* that's what this line of code (below) does!
*
* and that's what this class 'Cart' does!
*
* $cart->addItem($id, $qty, $catalog[$id]);
*
* of course, you have to use session in the addItem() call in order for it to persistence
* the session!
*
* this is a very elegance way to program a shopping cart by providing a lot of different catalogs
* with different kinds of items and depending on what a particular shopper is looking at which
* catalog, you pass that catalog to this function 'addItem'.
*
* you normally do your cataloging coding logic in the "external" controller to select and switch
* which catalog to pass in to function 'addItem'.
*
* if you implement your session properly in the addItem() call (in controller) it will persist the session for you!
* $cart = new Cart(); // this is should be in the external controller
*
* the call to $cart = $cart->addItem() adds the items in the array variable $item (or referring to as $this->item)
*
* $base->set('cart', $cart); // you need to persist the session as well!
*
* then in the view, you can iterate through the array variable $item using foreach(), for example:
*
* $cart = $base->get('cart'); // assuming you have $base as an instance of class Base
*
* foreach ($cart->item as $id => $product)
*
* with $id being the product id contains in the catalog!
*
* and $product being the product/item profile: product name, price, description, url, image, etc.
*
* from this basic generic guideline you should be able to build a very sophisticated ecommerce
* application, large or small easily and powerfully!
*
* there you have it!
*
* and have fun at it!
*/
?>
As you can see from the above example, you can have all kinds of catalogs displaying to shoppers and when a shopper selects a particular item, your "external" controller should be able to detect which catalog is being used. There are lots of ways to implement that feature and one of them is to send it in a form that contains the item profile along with the catalog name. For example:
<?php
/**
* for the form's 'action' attribute it contains a route called 'cart/add'
* this will route to a controller class called Cart and its method called add.
*
* of course, you have to implement it in an MVC scheme or else change it to: cart.php.
* id being the product id
* qty being the product qty that a shopper is buying
* catalog is the catalog name that the shopper is buying the product from
*/
<form action="cart/add" method="post">
<input type="hidden" name="id" value="<?=$id?>" />
<input type="hidden" name="qty" value="1" />
<input type="hidden" name="catalog" value="<?=$catalog?>" />
<input type="submit" name="submit" value="Add to cart" />
</form>
?>
As far as the catalogs are concern, they are basically arrays of items/products that contain the product profile or attributes: product name, id, price, description, url, image, etc.
How you implement that catalog feature is up to you. One way is to store catalog items in the database and then query the database to pull the catalog items and then put them in the array and then displaying them in your catalog/website for shoppers to view/purchase.
The possibilities are endless, the sky is the limit!
There you have it!
Have fun programming sophisticated eccomerce platforms and don't forget to thank me later!!!
A developer - also known as a programmer, coder or software engineer - is an IT professional who uses programming languages to create computer software.
What do software developers do?
Developers write, test, debug and maintain applications. Developer roles can vary widely depending on the type of organization. They are usually employed by either the technology companies that create off-the-shelf software or by end-user organizations - both in the public and private sectors - who develop bespoke applications. But coding, as we will see below, is just one important element of an increasingly broad role.
What skills do you need to become a software developer?
To answer that, here is an article by Mark Samuels that appeared on ZDNet which tells you everything about the programmer role and how it is changing.
Developers need strong technical aptitude. Some programmer positions will require a degree in a relevant field such as computer science, information technology, mathematics or engineering. While education is important, the fast-evolving nature of software development means on-the-job experience will be the key to successful career development.
What programming languages do software developers use?
Software development is a constant work in progress. The 2020 Harvey Nash Tech Survey found that a third of developers believe their current skills will only be relevant for the next three years.
Right now (as of the decade of 2020), JavaScript is the most popular programming language with 13.8 million developers, according to SlashData. The UK firm estimates that the JavaScript community accounts for a big chunk of the 24.3 million active developers worldwide.
SlashData says the second largest population of 10.1 million developers are Python users, which is popular with machine-learning specialists, while there are now 9.4 million Java developers. These top-three programming languages are the same as developer analyst firm RedMonk's rankings, which are based on data from GitHub and Stack Overflow.
Other popular programming languages include C/C++, C#, PHP, Kotlin, Swift, Go, Ruby, Objective C, Rust and Lua.
Language popularity can be cyclical. Take the recent re-emergence of Fortran in Tiobe's programming index at 20th position, up from 34th spot a year ago. Fortran emerged from IBM in the 1950s but remains popular in scientific computing.
What makes a good software developer?
Rob Grimsey, director at recruiter Harvey Nash, says there are many attributes to a good developer - and inevitably 'good' means different things to different organizations.
"What everyone will look for as a base requirement, of course, is a high degree of technical capability, founded on solid coding principles and the ability to work well in a variety of development environments," he says.
However, there's a further dimension to being a good developer that goes beyond a strong grasp of coding languages. Grimsey says a good developer is part of a team, especially with the modern focus on Agile software development. Agile is a set of collaborative methods and practices for producing software code faster and more efficiently.
"Developers might be involved in a daily stand-up and other interactions. The ability to communicate, contribute ideas, and understand the wider business context of the organization's requirements - all of these are crucial. Developers are having to play a more interactive role and help bring ideas to life," says Grimsey.
What's the demand like for software developers?
The simple answer is high. Skills shortages were bad enough before the pandemic - and Harvey Nash reports demand continues to outstrip supply today, especially in software development, cybersecurity, and data. "There is high demand for developers and it seems to be getting higher all the time," confirms Grimsey.
Take job listings for PHP, which is a commonly used but not particularly loved programming language. The number of entry-level PHP developer roles has increased a massive 834% since January 2020, making it the fastest-growing tech job across the industry, according to Indeed's data.
When the first UK lockdown began in March, Harvey Nash saw a pause in recruitment for many kinds of roles - but not for developers. Grimsey say developers were essential in enabling businesses to go through rapid digital transformation. Companies used collaborative technologies to tap into a wider talent pool from around the globe. However, the battle for talent remains fierce.
"Businesses have realized as a result of COVID, and the new remote-working model, that they can recruit from a much wider geographic spread, which is positive. But even so, that doesn't solve the problem. If you're a good developer looking for work, you shouldn't be looking for very long," he says.
What's the demand like for software development training?
Once again, the answer is high. Computer programming and software development were the top choices for people looking to improve their employment opportunities in 2020, according to technology firm Red Hat, with almost one in 20 adults taking up coding or some form of software development training last year.
Expect demand to continue to rise as we leave lockdown. The new normal of work will bring a lot of changes, but one enduring theme will be upskilling and learning new programming language tricks, with many of the most popular courses - from specialists like Coursera, Udemy, Pluralsight and Udacity - available for free or with a subscription.
Industry experts suggest there is already evidence of software development skills spreading beyond the programming community. Warren Breakstone, managing director and chief product officer for data management solutions at S&P Global Market Intelligence, believes technical knowledge has become more widely accessible.
"The next generation of clients we have are coming out of school and they already know Python and R. Rather just knowing how to use Microsoft products, they're coming out with expertise and knowledge around these newer development methodologies, such as Python, which makes data, data analysis and data science far more accessible," he says.
How big a threat is low-code/no-code development to software developers?
The democratization of software development knowledge isn't the only threat to established coders. Emerging technology might well help to fill part of the IT skills gap in the form of no-code/low-code development tools.
The tools cut, as much as possible, the hands-on knowledge required to build software. Tech analyst firm Forrester predicts the low-code market will grow 40% annually to top $21 billion by 2022, while fellow analyst Gartner forecasts low-code platforms will account for 65% of all app development by 2024.
However, it's important to state that the end of hands-on development is far from certain. Sophisticated applications will always require a professional programmer's skills. And there is some hope that no-code tools can free-up developers to work on some of those higher-level business engagement tasks that senior managers are so keen for coders to assume.
"Low-code won't kill the demand for developers but rather will mean that they need multiple skills," says Harvey Nash's Grimsey. "They'll be looked to as problem solvers with full-stack capabilities. So they won't only be involved in writing code for the core application build, but ultimately the full journey of a piece of software or application."
What's the key to being a successful software developer?
Tarah Lourens, chief product and technology officer at property specialist Rightmove, is a former developer, so she understands the kinds of skills that will help talented software engineers stand out from the crowd. Like others above, she suggests coding is just a crucial jumping-off point for successful developers.
"I've always been passionate that the right mindset is less about the coding and more about what we are trying to apply this technology to," she says. "We need people who can find the right balance between building great code and delivering business outcomes. The more you can do that, the further you're going to go."
That's a sentiment that resonates with Boots CIO Rich Corbridge, who says that having an eye on innovation - and using your creative ideas to help solve business challenges - is likely to be a key marker for long-term software development success. That's certainly something he's seen during the coronavirus pandemic at Boots.
"Some of the best things that we've seen coming out in the past 12 months have been inspired by engineers sat around and going, 'What if we did this?' And that ranges from true coding of new stuff all the way through to the implementation of a tool like Adobe Audience Manager and considering 'what if we did something differently; what happens to the speed of the site or the ability to transact?'"
What roles can software developers move into?
The most obvious step is to senior programmer. As well as coding and testing, senior developers will start to work more closely with the business to identify their business requirements from software. This kind of engagement leads some developers into business analyst and possibly enterprise architect roles, where the emphasis is on investigating and developing an overall application strategy for the business.
Developers who get a taste for leading others can step into team leadership roles. Those who want to go further up the career ladder still can explore project management roles, where their experience of developing software can be used to help lead specific technology initiatives. What's more, the increasing use of Agile software development principles across the business means experienced developers with good engagement skills are likely to be in high demand.
How can software developers step up into more senior positions?
The key to stepping up is going beyond coding. Modern developers need to think about how their knowledge can help the business create value from technology. Boots' Corbridge says his organization tasks its senior developers with making sure the business gets the most from its vendor partners, such as Cognizant, TCS and IBM.
"We tend to have more of the lead engineer role leading those partners in what they do," he explains. "Our skill set is around being able to touch and see what's going on across the development of their products. People who have the capability to be close to the business and understand what the business needs, and where the product is going to keep us up to date."
Making the most of partners is not always a straightforward task. Like so many other modern organisations, Boots is keen to use Agile software development techniques. Corbridge says it's his senior developers' role to ensure that the software that his team and its partners produce can be adapted flexibly as business requirements change.
"If we're doing fixed-price deliverables in an Agile world, the two things don't make easy bedfellows. So trying to manage any of our partners to a fixed-time contract - but against an agile burn-rate framework, keeping on top of where that's going and how that's working - has been a big lead engineer-type role in the past 12 months or so," he says.
What's the pay for a software developer?
Glassdoor suggests the average pay for a developer in the UK is around £40,000 (for the current timeframe of 2020 to 2024), although rates and pay vary significantly with experience, skill and geography and as time moves into the future. Skill-training platform CodinGame suggests developers in the US are likely to command the biggest salary, with an average software engineer grossing $95,744 per year.
Coding specialist Stack Overflow reports that Scala is the programming language associated with the highest pay in the US, with an average salary of $150,000. Other languages with a salary of at least $120,000 include Go, Objective-C, Kotlin, Perl, Ruby, Rust, C, Swift, Haskell, Assembly, Bash/Shell/PowerShell, C++, Java, Python, and TypeScript.
What's the future of the software developer?
Despite ongoing evolution in coding techniques and the rise of no-code development, the role of software developer is not under threat - but it is changing. Harvey Nash's Grimsey says the role is becoming more consultative with more stakeholder-facing emphasis.
"It's a shift that's already begun - the role will be about a whole lot more than writing lines of code, with many complementary skills required," he says. "Developers may get more involved in discussing the brief with their client, fleshing it out and iterating ideas."
Rightmove's Lourens also recognizes this shift. She says successful software engineering is no longer about what languages you know and is more about how developers can apply their mindset and aptitudes to the challenges the business faces.
"Things are moving so fast now that at the time you're assessing somebody on a language, it's already changed - there's a new version. I think over time, successful software engineering will become more and more about somebody's mindset first and then about the specific technical skills they've got," she says.
"I think that should open up the industry, too. For so long, success in the technology industry has been about what exposure you've had and what systems you've built in what language, which immediately closes down the opportunities for people. So, from a diversity point of view, I think the change in mindset is also a potential enabler."
The W3 Consortium (W3C) is a group founded by Tim Berners-Lee in 1994 to allow Web developers develop interoperable technologies (specifications, guidelines, software, and tools) to lead the Web to its full potential. The World Wide Web was invented by Tim Berners-Lee in 1989.
Without this group, who knows what the Web standard would be today if each group (or technology company) develops their own seperate Web standard for all of us to use?
Remember the browsers war between Netscape and Microsoft in the 1990s? Two different technology companies wanting their own broswer standard to be adopted by users and the casualty of that war, which is being felt today and beyond, is that we have to program code using two different standards to port to both browser standards.
Since then, the W3C has taken the bull by the horns and basically sets most (if not all) of the Web standards we enjoy today. A very nice reprieve from the constant squabble of the old days.
The following lists the standard specifications set by the W3C.
CSS2: Cascading Style Sheets 2.1 Specification
Descriptions of all CSS specifications
It is typically being used by website owners who need to upload their website files from their local computer to a remote server that their website is hosting on. You can also use FileZilla to download files from a remote server that your website is hosting on as well.
So it is a file transfer application using an FTP file transferring protocol. So FTP is an acronym for File Transfer Protocol.
As always, lots of tutorials on this subject are available on the Internet, particularly on YouTube and elsewhere in HTML. So instead of actually doing a tutorial that can be found easily on the Internet, I'm going to just refer you to those tutorials and let you follow those tutorials instead. Why is there a need for me to do a tutorial that is readily available on the Internet? The answer is that absolutely no!
So here we go:
Here are brief summaries of steps on how to configure FileZilla client after you'd watched tutorials listed above and as well as having FileZilla downloaded and installed onto your computer.
Download the FileZilla onto your computer.
Once you've downloaded it, extract it using zip extracting applications like WinZip Express Zip WinRAR or WinRAR here! PeaZip
Collecting FTP Details
After you installed FileZilla onto your local computer, you now are ready for the transferring process. But first thing first, you need to gather the FTP details of your hosting account. Each hosting provider is different in how they layout their FTP information. For Hostinger users, the information is located in the hPanel's menu, under:
Files -> FTP Accounts
Most hosting providers have a dashboard area or webspace area where you can see options to choose to go into more specific tasks. For example, for my hosting provider, it has a dashboard that shows all kinds of options for me to choose. For example:

Here, when I click on an FTP Manager, it takes me to an FTP manager area where I can setup/create FTP accounts. In the FTP manager I can create an account by creating a username and a password. I will need these information that I created to be used in the FileZilla. Here is what the inforamtion in the FTP manager looks like:

Once you have an FTP information, you can use it to configure FileZilla. Now all you have to do is click on your FileZilla icon to open it and you'll see a screen that looks like the following:

As you can see in the diagram above, on the left side is for a local working area or section. This is where you can configure your connection information and selecting files or directories to upload to a destination on the right side. On the right side is a remote site or destination area to upload to.
In the above diagram, you can provide information to do a "quick connect" connection. However, I strongly suggest that you don't use a quick connect but instead go through a longer connect, which I will detail it for you. It will save you time later on. A quick connect doesn't remember your connection setting after your computer is turned off, while a longer connection will.
Here is for the longer and more efficient connection:
Click on "File" at the top left corner of the diagram shown above. The drop-down menu will reveal several options but you want to choose "Site Manager" option. A site manager screen should open up and should looks like the following:

Pay close attention to a section called "Select Entry" where all of your FTP accounts are to be created. In my case, I have four FTP accounts: one account to connect to a Monday-Sunday website FTP hosting account; another to connect to a Noon2Noon.NET FTP hosting account; another to a Postal FTP hosting account; and finally to a ZeroNilZilch FTP hosting account.
So in my case, I have four different hosting service providers; and therefore, I need to have four different entry names (Monday-Sunday, Noon2Noon.NET, Postal, ZeroNilZilch), each connecting to its individual FTP account.
So in your case, the "Select Entry" section and "My Sites" area should be empty because you haven't create a "New Site" yet.
To create a "New Site" entry name similar to the four shown in my case, click on another option called "New Site" down below at the bottom of the diagram. Once you click on "New Site" option, an entry inside the "Select Entry" under "My Sites" area will appear for you to enter an entry name similar to the four entry names that I've created.
Name your entry name any name you like. It's just a name to differentiate from one entry name to another.
Once you created an entry name, you need to configure FileZilla to connect to your FTP hosting account by hi-lighting an entry name similar to what is shown with ZeroNilZilch right now. As you can see, once you hi-light it, the entire diagram flickers and changes the configruation and reveals input boxes for you to enter an FTP information.
For example, for me, I hi-lighted or selected 'ZeroNilZilch' in the "Select Entry" section, and then to the right, I entered 'zeronilzilch.com' in the host box.
This information is obtained from my FTP hosting account created earlier. In your case, you can get this information and the rest of the FTP information from your FTP hosting account.
For port, I use 21, which is a common port for a shared hosting. All you need to know about port is that if you rent or use a free web hosting from any vendor, use port 21, because most likely they're shared hosting. All shared hostings use port 21.
For protocol, select FTP; for encryption select FTP over TLS (just like what it looks like on the screen); for logon type, use 'Normal'; for user (or username) enter the actual FTP username you got from your hosting vendor; likewise, for the FTP password.
That is it! Nothing else to enter. Very easy! Now all you have to do is click on the button "Connect" to connect to your FTP hosting server to begin the transfer process.
After you click on "Connect" it should looks similar to the partial diagram shown below. I show only partial diagram to avoid revealing my other information to the public. But this partial diagram should give you a good idea of how it works.

As you can see, it is very easy to use FileZilla.
Now since you've created your connection the longer and more efficient way, next time you need to connect to your FTP account, just open up your FileZilla application that should looks like the default view similar to the one that has a "quick connect" option on it (shown earlier).
Yes, that is the default view of FileZilla (shown earlier) allowing you to either do a "quick connect" or do a longer more efficient connect.
So since you went through a series of steps to do a longer and more efficient connect already, now all you have to do is click on one of two things:
First the hard way:
You can click on "File" at the top left corner of the diagram shown above. The drop-down menu will reveal several options but you want to choose "Site Manager" option.
A site manager screen should open up and should looks like the "Site Manager" diagram shown earlier. From there, all you have to do is hi-light an entry name to make it looks like the one shown on "ZeroNilZilch." This will activate your FTP account setting and ready to be connected to. Next, just click on the "Connect" button and it will try to connect to your FTP hosting account.
Well, that was somewhat the hard way. Sort of!
Now the easy way:
The same thing: you can click on "down arrow" or a drop-down menu just below "File" at the top left corner of the diagram shown above. The drop-down menu will reveal an entry name (or several entry names if you have more than one as in my case).
Now all you have to do is click on an entry name in the drop-down menu and a "Site Manager" showing your entry name is shown ready to be connected to your FTP hosting account. Next, just click on "Connect" button and it will try to connect to your FTP hosting account.
Once connected it should looks something like a partial diagram shown below.

Since it is a partial listing of the actual full view, you're not able to see all options you can do with the connection. You'll have to make use your FileZilla on your own from here on. It is very easy because all the hard part has been explained and now is just the easy part.
Well actually, you can see a somewhat full view of the default view shown earlier and you should get a good idea of how you can select a particular file or directory to upload to.
But briefly, as you can see from the above diagram, there are two parts: one on the left side contains your local file directories where you can select and upload them to the destination on the right side. Simple enough?
On the left, because of a partial listing, I am not able to show you that you can actually select or pull down a drop-down menu to select any directory from your local computer to upload to the destination on the right side. Yes, you can select or pull down a drop-dwon menu on the left side and select any directories or files to upload to the destination on the right side.
Likewise, on the right side, you can select (or pull down a menu--well, mainly select) a directory to receive the content being uploaded to it. In other words, to upload a file or files or directory or directories, you need to know where in directory destination you want to upload the content from the left side to on the right side. Self-explanatory!
Once you've selected the destination directory on the right, and then you can go ahead and upload the content on the left side by hi-lighting or selecting it and right-click it to reveal several options. One of the options is "upload" and select "upload" to upload it. Self-explanatory!
Likewise, on the right, you select a particular file or files or directory or directories by hi-lighting it and then right-click it to reveal several options. One of the options is "download" and click on it to download. Self-explanatory!
That is it! Have fun using FileZilla.
For a very good introductory tutorial on the Web, please check out the following tutorials:
The MVC Pattern: PHP, MVC and Best Practices The MVC Pattern and PHP, Part 1 The MVC Pattern and PHP, Part 2 The MVC Pattern: An Introduction to the Front Controller Pattern, Part 1 The MVC Pattern: An Introduction to the Front Controller Pattern, Part 2For a more advanced pattern methodology, please check out MVVM (Model-View-ViewModel). MVVM was invented by Microsoft for desktop programming in 2005 using event driven programming techniques.
MVVM was invented by Microsoft architects Ken Cooper and Ted Peters specifically to simplify event-driven programming of user interfaces, i.e., GUI applications. The pattern was incorporated into Windows Presentation Foundation (WPF) (Microsoft's .NET graphics system) and Silverlight (WPF's Internet application derivative).
MVVM is more suiteable for desktop programming than Web programming.
So if you're programming for the Web use MVC and if you're programming for the desktop use MVVM.
Advanced Pattern: The advantages of MVVM over MVC Advanced Pattern MVVM For Desktop: Model-View-ViewModel Design PatternFor a more advanced pattern methodology using MVC, please check out on the 'how to build your own framework':
Advanced Pattern in MVC: Code Your Own PHP MVC Framework Advanced Pattern MVC and PHP: A Beginner's Guide To MVC For The Web ProgrammingAn MVC is an acronym for Model View Controller.
It is a methodology to uniform the way people program applications. Remember that in programming, programmers tend to have their own unique way of doing things and that causes a lot of confusions, especially in a team work where programmers are working in the same project. There is no way of knowing what each programmer is trying to do in the same project. There is a compatibility issue.
There is no uniform pattern way of doing things; each programmer is doing things each his/her own way of doing things; for example, in a team work in the same organization working on the same project, one programmer puts data handling with the organization of that data while another programmer puts the same data handling with the displaying of that data to users; and the two programmers are completely oblivious to what the other programmer is trying to do.
This causes the finished product to be in-efficient, in-compatible, and not robust and not to mention the cost of having programmers to do other similar projects that take a long time to complete because of the codes are not re-usable.
So to be efficient, robust, scalable, upgradable, re-usable, and easy to maintain, it has to be a unique way of doing things for all programmers to understand and work in a uniform way so that all programmers can know systematically what the other programmers are doing in the same project, even if each programmer is located far away from each other and haven't seen each other's actual work.
To solve this issue, the MVC was developed.
To understand the concept of MVC, think of it in term of an organization mentioned above where there is a manager, some programmers, and the customers who want to get the application done.
The customer is the view presenting to the manager of what to be done, telling the manager the criterio of what need to be done. For example, the customer may wants the website that has ecommerce and social media applications capability installed in it.
The manager is the controller, handling the organization (or criterio) of the task dictating and given by the customer.
The programmers are the model handling of data or instructions given by the manager and using those instructions from the manager to proceed to do all of the programming work.
Notice that the manager, or the controller, does not know how programmers perform their tasks for the project: he/she doesn't care how their programmers do their jobs as long as their programmers perform the task that meets the criterio given to them.
Likewise, the programmers know nothing about who the customer is and what he/she looks like or wants. The programmers don't really care who the customers are; all they care about is getting the task done.
Likewise, the customer knows nothing about who the programmers are and what they look like or where they're at or from. The customer only cares about is getting the website completed in the agreed timeframe.
And also, the programmers don't know how the manager got the instructions or whom he'd or she'd got it from. The programmers don't know what the heck the manager is doing either: the programmers just don't care what the manager is doing or how he/she is doing. It's not their job to know what the manager is doing.
Keep this seperation of concern in mind when you're dealing with MVC pattern.
As you can see, the three parties are completely independence of one another: in other words, they don't need to know what the other is doing or how the other is doing things. They all can do things in their own seperate unique ways without intertwine with one another.
Now imagine you're a large or small organization where you have lots of programmers working on all kinds of applications large or small and those programmers are spreading all over the world.
If all these programmers know MVC pattern, they can work on the same projects in different part of the world without knowing what the other programmers are doing on the same projects that they're working on.
This is the beauty of an MVC pattern where one group of developers working on the same project as the other group is located in far away from each other and they still can accomplish the same project without knowing what the other groups are doing.
In an MVC pattern, each party is seperate from one another and each party knows nothing about what the other party is doing. In an MVC pattern, each party doesn't need to know what the other party is doing as long as each party is doing its job in a unique/uniform way using MVC pattern.
Let's review: the customer requests to the manager telling the manager of what kind of application needs to be done; the manager, in turn, tells the programmers what tasks need to be done. That is all! Nothing else!
The customer doesn't know what the manager or the programmers are doing as long as the application gets done; while at the same time, the manager doesn't need to know what the programmers are doing as long as the task of getting the application done; and likewise, the programmers don't need to know what the customer looks like and how that customer's exact words to the manager -- it doesn't matter.
When you approach to building an application in an MVC pattern, think of the above analogy -- it will help you a lot.
Think of the analogy above and relate it to this: The view V is the display page (or customer in this case); the model M is the data (programmer in this case); the controller C is the coordinator, organizer, delegator, dictator, controller (or manager in this case).
Here is a brief example on how to program in an MVC pattern.
As you maybe well know that an HTML page is just nothing more than plain HTML texts along with some anchor links, buttons, or forms. That's all an HTML page is. And that is the view V.
Typically, the index.php front page or a catalog page or an HTML form is the view 'V' rendering the page to the customers/users to allow customer/users to navigate through the pages looking to do/order things.
In the index.php front page or a catalog page or form, there should be some buttons or links for customers/users to navigate to the products or area of interest.
That's all the view 'V' is; nothing special: just HTML pages or forms that contain contents and buttons or links. Nothing else!
Now when a customer/user clicks on the button or link, it redirects the customer/user to another part of the website or sometimes to another remote site.
Now before it reaches another part of the website or another website remotely, it has to go through a controller 'C' (or a middle man or a manager in our case). It has to hand over the instructions to the manager to decide on what to do next. Logically, a manager will hand over the instructions to programmers to start performing the tasks.
Remember that the programmers are the model M who do all the heavy work. The model also known as the data.
In the case of a button or link, it contains a url to redirect to:
'http://www.example.com/index.php?site/controller'
Before I show you how to parse this url (above), I want to show you the server access command using .htaccess file. Put this file in the same directory as your index.php in the root directory of your project. This index.php file is typically called a starting script file.
This .htaccess file is for the server to read before each time a website is loaded. This is sort of the instructions for the server on what to do before loading the website. You can tell the server what to do before loading your website using Apache's mod_rewrite commands.
This is the hand over the instructions to the programmers using routes.
The .htaccess file controls a number of ways that a website can be accessed, blocked, and redirected. It does this using a series of one or more rewrite rules. These rewrites are made possible by Apache's mod_rewrite module.
mod_rewrite provides a way to modify incoming URL requests, dynamically, based on regular expression rules. This allows you to map arbitrary URLs onto your internal URL structure in any way you like. For example, control how your querystring is formatted.
Open up your text editor and create a file called .htaccess and put the following content inside it.
File: .htaccess
# please remove all these textual comments because it may cause problems!
# the .htaccess file starts with this line
RewriteEngine on
# the above line says turn on the Apache server
RewriteBase /
# the above line says look for content after http://www.example.com/
# with '/' being the last '/' after '.com'
# next two lines say if a directory or a file exists, use it directly
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
# with !-d for a directory and !-f for file
# otherwise forward it to index.php (using the rule shown below)
# in other words, if none of the two conditions above is met or true,
# go to execute index.php, with index.php being the starting script file, i.e.:
# http://www.example.com/index.php
RewriteRule ^(.*)$ index.php?url=$1 [L,QSA]
# continuing on above line: after the 'index.php?' is the querystring
# this is like: ?controller/action/param1/param2/para3/para4/para5/...
# so this string: url=$1 [L,QSA] is just for the server to read!
# the "L" stands for link, the Q for query, S for string, A for append
# the string "url" is the name of the querystring that you will need to
# refer to when you parse your route. see function splitUrl() later on!
# the below two lines are just more rules and server options
# the first allow json file to go through and the second for options
RewriteRule \.(json)$ - [F]
Options -Indexes
# you don't need to understand any of this content in this file
# just use it "AS IS" but don't forget to remove my textual description!
# one important note: don't forget to remove the RewriteBase / entirely
# if for some reason your website doesn't load!
# I found that for some shared hosting it causes a problem!
# so if it doesn't load, just remove the RewriteBase / entirely
# for more on this topic, please Google the Web and there are
# plenty of tutorials on the Internet on the topic of .htaccess file!
What the above .htaccess file does is allowing you to do like this on your url route:
<a href="http://www.example.com/controller/action/param1/param2/param3/...">link</a>
or just:
<a href="controller/action/param1/param2/param3/...">link</a>
Normally you would have to send your "GET" url string like this:
<a href="http://www.example.com/?controller=site&action=signup¶m1=value1¶m2=value2¶m3=value3&...">link</a>
The above link will route the route to the class SiteController with 'site' is the controller 'C' and 'signup' is the action or the method in the class SiteController. The rest are just "GET" method querystring parameters.
But with the .htaccess file you can do a shortcut to make your life easier by using URL rewriting rules or mod_rewrite rules.
So this is without URL rewriting rule: <a href="http://www.example.com/?controller=site&action=signup¶m1=value1¶m2=value2¶m3=value3&...">link</a>
This is with URL rewriting rule: <a href="http://www.example.com/site/signup/value1/value2/value3/...">link</a>
or just a shortcut:
This is with URL rewriting rule: <a href="site/signup/value1/value2/value3/...">link</a>
As you can see, it is much simplier using URL rewriting rules in the .htaccess file.
For img:
<img src="image/picture_1.jpg">
Notice that for img tag, there is no route needed. The img tags are typically being used in the view to display images; and therefore, routes are not needed. So you simply specify the src attribute that points to the directory of the image as you normally do in a non-MVC way.
For forms:
<form method="GET" action="http://www.example.com/site/signup/param1/param2/param3/..."></form>
Or just:
<form method="GET" action="site/signup/param1/param2/param3/..."></form>
For buttons:
<button type="button" onclick="http://www.example.com/site/signup/param1/param2/param3/..."></button>
Or just:
<button type="button" onclick="site/signup/param1/param2/param3/..."></button>
Basically, instead of having to write a complete route of
<a href="http://www.example.com/site/signup/param1/param2/param3/...">link</a>
on every link that you need, all you have to do is write just the querystring:
<a href="site/signup/param1/param2/param3/...">link</a>.
That's what the .htaccess file is for: allowing you to do a shortcut!
You will often route your form like this:
<form action="http://www.example.com/user/signup/param1/param2/param3/..." method="GET">
Or in a shortcut like this:
<form action="user/signup/param1/param2/param3/..." method="GET">
to route your user to the signup page. Notice that this is for a "GET" method. For a "POST" method see below.
The user part is the controller 'C' and the signup is the action. The rest are just "GET" method querystring.
If it is user/signup/id/guest/vip/ then user (the first part is always the controller 'C' and the second part signup is always the action, and the rest are extra GET parameters or querystring to send to the route.
In this case, there are three extra parameters that are being sent to the route: id, guest, and vip.
Please check out tutorials on the Internet to learn all these terms. Please check the following tutorial for more:
The MVC Pattern and PHPThe two most important terms are controller and action. Make sure you know what these two are and how to use them.
Hint: the controller is the class and the action is the method of the controller class. For example: user/signup.
<?php
// this is the controller
class User
{
// this is the action
public function signup()
{
// method code
}
}
?>
Note that you can use "POST" method as well and it will route your route via a "POST" and not via a "GET". For example:
<?php
<form action="user/signup" method="post">
<input type="hidden" name="id" value="My_id_123">
<input type="hidden" name="guest" value="This is the guest content">
<input type="hidden" name="vip" value="This is the vip content">
<input type="submit" value="Submit">
</form>
?>
The above form sends the POST variables to the route: user/signup. The .htaccess file routes this request through a normal HTTP REQUEST channel using a POST method.
DO NOT add the querystring in the POST method like you do with a GET method.
This is illegal: <form action="user/signup/id/guest/vip/" method="post"></form>
This is the correct way:
<?php
<form action="user/signup" method="post">
<label for="id">Enter your id:</label><br>
<input type="text" name="id" value="My_id_123">
<label for="guest">Enter your name:</label><br>
<input type="text" name="guest" value="This is the guest content">
<label for="vip">Enter your vip number:</label><br>
<input type="text" name="vip" value="This is the vip content">
<input type="submit" value="Submit">
</form>
?>
Remember that you handle a POST request the usual way where you send it to; for example, in the above case, it sends to the controller or class 'User' to execute the method signup(). Somewhere in the class 'User', particularly in the method signup(), is where you handle the request by doing this: $_POST['id'], $_POST['guest'], $_POST['vip'].
The keyword here is 'somewhere' because as you know the HTTP REQUEST once it is sent, it is available everywhere. So for class 'User', it is available everywhere inside it. Self-explanatory!
Now we need to parse the route or querystring.
This is also part of the handover of the instructions to programmers. Remember that managers only coordinate, delegate, and dictate the tasks to employees and do very little work.
<?php
// don't forget to put this class route in the folder: path/to
// or put it in whatever folder names you name them!
// 'path', 'to' are actually folder names containing the models or classes
namespace path/to;
class route
{
public $base = array();
// now your main controller class will need to call
// this method init()
// you can do it inside your index.php starting file or from
// inside your main application file, for example:
// $route = new route();
// $route->init();
// for an example of a starting script file, see my other tutorial
// called "how to autoload classes using SPL" and there is an
// index.php file example shown at the very end of that tutorial!
// see a lengthy explanation of the difference between an
// index.php starting script file and the index.php/index.html
// front page view [below]!
public function init()
{
// class Base is the base controller class
// I haven't written it yet! Maybe I won't!
// did I mentioned that this is a very brief tutorial?
// this will not be a complete tutorial! just to give you
// an idea to move forward!
// check out the Internet on topic of "MVC" base controller class!
// basically, the "controller base class" is the main application
// class that handles all the logic of the entire application.
// see an example in my other tutorial called
// "how to autoload classes using SPL"
// manager coordinates, delegates, and dictates the tasks to employees
$this->base = new Base();
// get the url fragments from the url
$this->splitUrl();
// you need to require/include the appropriate file directory
require_once 'resource/dispatch/dispatcher.php';
$dispatch = new dispatcher();
// basically test to see if the url fragment in $x1 exists!
// suppose that a visitor of your website types in the
// url bar: example.com and the browser will try to
// to load: http://www.example.com/index.php
// now when it gets to splitUrl() it will return:
// $x1 is null, $x2 is null, $x3 is null, etc.
if (!isset($this->base->x1))
{
// so it comes here because $x1 is null!
// it will load the default file index page!
// don't be confused the default index page file with
// the starting index.php file!
// the two are completely different from one another!
// the default index.php/index.html page is your index
// front page typically can be found in the view, while
// the starting script file index.php is the file to
// jumpstart the application!
// for an example of the default index.php/index.html
// front page, see class dispatcher->init()
// where the code that looks like this:
// manager coordinates, delegates, and dictates the tasks to employees
// basically the manager is handling the finished product to the customer
// for inspection to see if it fits the requirement!
// $this->base->render('index');
// as you can see, the statement above renders the view's
// index file: index.php/index.html in the 'view' folder!
// that's what the statement below is doing!
$dispatch->init();
// for an example of the script's index.php starting file,
// see my other tutorial called "how to autoload classes using SPL"
// and at the very end of that tutorial,
// there is a script file called index.php
// this script index.php starting file should be at the root
// of your application!
// if you look in my other tutorial called 'getting started
// programming for beginners', there is a section called
// 'How to Install WAMP on Windows', particulary, step 10.
// At the very end of that section where I show a
// localhost containing a sample application folder called
// "MyFirstWebsite"
// inside that folder there are only three items: 'css' folder,
// 'image' folder and the main starting script file 'index.php'
}
elseif (method_exists('dispatcher', $this->base->x1))
{
// now here, $x1 is NOT null!
// this is the case where you can do in the view like this:
// <a href="about">About</a>
// <a href="affiliate">Afilliate</a>
// <a href="signup">Signup</a>
// <a href="login">Login</a>
// remember what a view is?
// a view "V" contains only three main things: a page (i.e. webpage,
// catalog page, form, etc.), some links, and some buttons!
// that's all a view is
// the above example will load the controller page:
// dispatcher->about(), dispatcher->affiliate(),
// dispatcher->signup(), dispatcher->login()
// now what happens if you put an index "home" link/route in
// the view like the following?
// <a href="index">Home</a>
// here, x1 = 'index' but there is no method called 'index'
// in the 'dispatcher' class!
// so it won't come here and it will fall into the default
// condition below and displays the 'index' home page!
// now what happens if you put a link/route in the view
// like the following?
// <a href="user/signup">Signup</a>
// <form action="user/signup"></form>
// <a href="user/signup/id/guest/vip">Signup</a>
// <form action="user/signup/id/guest/vip"></form>
// obviously, x1, x2, and x3, etc, are not null!
// and therefore, it will still come here as well with:
// $x1 = 'user'
// $x2 = 'signup'
// $x3 = 'id'
// $x4 = 'guest'
// $x5 = 'vip'
// in this case, only x1 and x2 are relevant and both will be
// dispatched to the appropriate controller.
// see class dispatcher->user() later on!
$method = $this->base->x1;
$dispatch->$method();
}
else
{
// this is the default condition!
// if none of the conditions above are met,
// it will load the default index.php page!
// now what happens if you put a link/route in the view
// like the following?
// <a href="index">Home<></a>
// <a href="unknown">Unkown Link</a>
// <a href="noroute">Not Sure</a>
// all will come here because x1 = index, unknown, or noroute
// and x2 is null!
// so none of the conditions above are met,
// so all three cases above will come here and
// load the default index.php page!
// note that for your "Home" link, you can use the domain name
// as well (your domain), for example:
// <a href="http://www.example.com">Home</a>
// I recommend that you use the domain name for your "Home" link
// to avoid problems!
// if you use index or other unknown/undefined method of the
// controller (as shown above), it might give you an error saying:
// "Can't load the page! Please check your url to make sure it is
// the correct link!"
// so using the domain name as your "Home" link ensures that it
// will load the default index.php page every time! no errors!
$dispatch->init();
// now what happens if you put a form route in the view
// like the following?
// <form action="unknown"></form>
// <input type="hidden" name="test" value="some test value">
// </form>
// it will come here also because x1 = unknown, and x2 is null!
// here is the problem: the browser is confused!
// some browsers will load the default index.php and some browsers
// don't know what to do and display an error: Can't load the page!
// notice that we're talking about forms and not anchors!
// so the browser is confused!
// if it is an anchor it is probably okay and not confused!
// to solve this problem, for forms use the correct route:
// user/login, cart/addtocart, etc.
// so be aware of these scenarios!
// in other words, make sure you specify the correct route/link!
}
}
// handling the incoming instructions from the view!
// if the controller exists then call the controller
// also store the properties in the main application object to
// be used later: $this->base->x1
public function splitUrl()
{
// if you look in the .htaccess file you'll see this:
// RewriteRule ^(.*)$ index.php?url=$1 [L,QSA]
// check if the url GET parameter is set
// now the 'url' part is where we test for!
if (isset($_GET['url']))
{
// load the url into url variable
$url = $_GET['url'];
// trim the url to remove slashes on right:
// user/signup/id/guest/vip/
// becomes:
// user/signup/id/guest/vip
$url = rtrim($url, '/');
// break the url into fragments:
// $url[0] = 'user', $url[1] = 'signup', $url[2] = 'id',
// $url[3] = 'guest', $url[4] = 'vip'
// what happens if a user types in the url bar like:
// http://www.example.com ?
// splitUrl() will try to split the GET parameters and $url is null!
// in other words, splitUrl() cannot split the GET parameter:
// there is none!
// and the foreach ($url) loop below will return null as well!
// and therefore, x1, x2, x3 also will be null!
// now what happens if you put a link/route like the following?
// <a href="about">About</a>
// <a href="affiliate">Afilliate</a>
// <a href="signup">Signup</a>
// <a href="login">Login</a>
// it will split the url and $url contains an array of one element:
// $url[0] = 'about'
// $url[0] = 'affiliate'
// $url[0] = 'signup'
// $url[0] = 'login'
// and therefore, x1 = 'about', 'affiliate', 'signup', 'login'
// and x2 and x3 are null!
$url = explode('/', $url);
// load the url fragments as the object property variables
// as x1, x2, x3 ....
// in other words, set the main application's properties!
// notice that in PHP, you can declare a property on the spot
// and set it on the spot as well! very neat, huh?
// this is exactly what happens in the method set() below!
// you need to write a set($property, $value) in your main
// application controller class (Base) as well as a get()
//
// put the following two methods in your main base controller
// public function set($property, $value)
// {
// $this->$property = $value;
// }
//
// usage get():
//
// $base->get('x1');
//
// will return the controller, i.e.: user
//
// public function get($key)
// {
// if (isset($this->$key))
// {
// return $this->$key;
// }
// else
// {
// return null;
// }
// }
foreach ($url as $key => $value)
{
$key++;
// this is basically setting class Base's properties
// so that we can use them later. see init() above!
// later, anywhere, we can do this:
// $base->x1, $base->x2, $base->x3
// this will become:
// x1 = $value, x2 = $value, x3 = $value ....
$this->base->set('x'.$key, $value);
}
} // end if (isset($_GET['url']))
} // end splitUrl()
} // end class route
?>
Next is the dispatcher to dispatch the controller to the correct external controller.
Remember that there are two forms of controller: internal controller and external controller.
In this case, the internal controller are the class route and class dispatcher.
The external controller are the controller that actually doing the actual request to the model and as well as dictating to the view to display the view.
If you look in the method "user()" of the controller class "dispatcher" below, it creates an external controller by calling the createController() to create an external controller.
This is the manager who dictates to the programmers.
Remember that the manager only coordinates the job and doesn't do any heavy work at all! The heavy work is being done by the programmers.
As you can see below, the manager only asks the programmers to hand over the work by doing this: $base = new Base(). Now the manager knows nothing about what the programmers are doing inside class Base.
Now programmers all over the world can get to work on classes in their own seperate unique ways and none of them need to know what the others are doing. This is the seperation of concern of an MVC.
This example only shows one class or model; however, in a normal project large or small, there are lots of classes or model to be built and those classes or model can be given to groups of developers all over the world. And each group can work independently of one another without needing to know what the other groups are doing.
<?php
class dispatcher
{
public $base = array();
// now class dispatcher's init function
public function init()
{
// this method only contains two lines!
$this->base = new Base();
$this->base->render('index');
// that's it!
// the above call to render() tells the view to render
// the actual file in the 'view' folder!
// it is the controller telling the view to display the page
// view!
// the above call to render() will render the default front page:
// resource/view/index.php or index.html
// here is an example of render()
// method render() renders the view.
// this render() is incomplete as of now because I want you to
// implement your own version of render to suite your objective!
// how you implement your version of render() is up to you!
// but I suggest that you implement it using only two arguments:
// $this->base->render($view, $template);
// with $template, you might find it very useful to send in,
// say, a theme, or even a model!
// how you do it, it's up to you!
// you can make improvements to this barebone render() to make it
// more robust and powerful!
// notice that render() below, $template is an array and is
// initialized to null and you can call it like this:
// $this->base->render('index');
// $this->base->render('contact');
// $this->base->render('about');
// $this->base->render('affiliate');
// below, the first argument is the page: index.php or contact.php
// the second argument is the template or theme page or model or
// whatever!
// notice that you don't need more than two arguments!
// put the following render() code in your main application
// base class similar to the example class Base()
// public function render($view, $template[] = null)
// {
// // setting the view template to default theme or whatever!
// // I won't show you the example and leave it for you
// // to implement in your own unique ways!
// // this "if" block needs more work to suite your objective!
// if ($template == null)
// {
// // set it to default theme or whatever!
// $template = 'default_theme';
// }
// // right here where you can branch out to different
// // view/files/themes
// // you can branch out to tidbits of snippets of code
// // view as well
// // right here, you can implement code that looks for
// // certain view and files that resides in a folder
// // it's a very good idea to implement code that can
// // handle view in its own folder.
// // that way you can put certain view in certain folders
// // for modularity purpose!
// // as stated earlier, how you implement your render()
// // is up to you!
// // but here is one possible way of doing it:
// // you implement your first argument that can receive
// // two items: view/index
// // with 'view' being the folder and index being the file!
// // you can call it like this:
// // $this->base->render('view/index');
// // $this->base->render('affiliate/index');
// // $this->base->render('about/index');
// // $this->base->render('profile/index');
// // OR
// // $this->base->render('catalog/index', $template);
// // $this->base->render('cart/index', $template);
// // $this->base->render('admin/index', $template);
// // $this->base->render('product/index', $template);
// // I won't show the latter case and leave it to you to do!
// // notice that you can add as many folder levels as you want, for example:
// // $this->base->render('index/folder1/folder2/folder3/folder4/', $model);
// // and explode them into:
// // $view[0] = 'index'
// // $view[1] = 'folder1'
// // $view[2] = 'folder2'
// // $view[3] = 'folder3'
// // $view[4] = 'folder4'
// // now let's illustrate the first case!
// // right here inside this render() you can do this:
// if (strpos($view, '/'))
// {
// $view = explode('/', $view);
// // now $view is an array of two elements: a folder and a file
// // $view[0] = 'view', $view[1] = 'index'
// // $view[0] = 'affiliate', $view[1] = 'index'
// // $view[0] = 'about', $view[1] = 'index'
// // $view[0] = 'profile', $view[1] = 'index'
// // from there, you can branch out to display the view from
// // its own folder!
// // as far as the second argument is concern, it is very
// // much can be anything: a theme or a model or anything!
// // right here where you refer to the view files
// // stored in the directory:
// $file = "resource/$view[0]/$view[1]" . '.php';
// if (file_exists($file))
// {
// require_once $file;
// }
// else
// {
// echo ("View file <b>resource/$view[0]/$view[1]</b>" .
// '.php not found');
// }
// }
// else
// {
// // you need to put all of your view files in the directory/folder
// // called 'resource/view' or whatever folder name you desire!
// $file = "resource/view/$view" . '.php';
// if (file_exists($file))
// {
// require_once $file;
// }
// else
// {
// echo ("View file <b>resource/view/$view</b>" .
// '.php not found');
// }
// }
// // as stated above you can add as many folder levels as you want, for example:
// // $this->base->render('index/folder1/folder2/folder3/folder4/', $model);
// // but that looks very awful and cluttered!
// // another way is to use some sort of label marker or flag to mark how many levels
// // of folders you are targetting for. for example:
// // if a label marker says 'index/flag1' you have only one level of folder,
// // if a label marker says 'index/flag2' you have only two levels of folders,
// // if a label marker says 'index/flag3' you have only three levels of folders,
// // if a label marker says 'index/flag4' you have only four levels of folders,
// // if a label marker says 'index/flag5' you have only five levels of folders,
//
// // that looks much cleaner and maybe better than the long list of folders example above.
//
// // and in the view pages you can do like these:
//
// // $this->base->render('index/flag1', $model);
// // $this->base->render('index/flag2', $model);
// // $this->base->render('index/flag3', $model);
// // $this->base->render('index/flag4', $model);
// // $this->base->render('index/flag5', $model);
// // of course, you can have other files as well beside 'index.php'
// // just replace your actual file name in place of 'index'
// // and inside this render() you can do this:
// if (strpos($view, '/'))
// {
// $view = explode('/', $view);
// // now $view is an array of two elements: a file and a folder flag where:
// // $view[0] = 'index' // which is a file: index.php
// // $view[1] = 'flag1' or 'flag2' or 'flag3' or 'flag4' or 'flag5'
//
// // after the explode(), these scenarios could happen.
// // I'm just showing the 1st argument to illustrate the example:
//
// // if render('index/flag1') ===> then $view[0] = 'index' and $view[1] = 'flag1'
// // if render('index/flag2') ===> then $view[0] = 'index' and $view[1] = 'flag2'
// // if render('index/flag3') ===> then $view[0] = 'index' and $view[1] = 'flag3'
// // if render('index/flag4') ===> then $view[0] = 'index' and $view[1] = 'flag4'
// // if render('index/flag5') ===> then $view[0] = 'index' and $view[1] = 'flag5'
// //
// // now we need to test the flag for the levels of folder after we exploded them:
// //
// // switch ($view[1])
// // {
// // case 'flag1':
// // $file = "view/$view[0]" . '.php'; // view/index.php
// // break;
//
// // case 'flag2':
// // // resource/view/index.php
// // $file = "resource/view/$view[0]" . '.php';
// // break;
//
// // case 'flag3':
// // // view/template/path/index.php
// // $file = "view/template/path/$view[0]" . '.php';
// // break;
//
// // case 'flag4':
// // // guide/local/dir/view/index.php
// // $file = "guide/local/dir/view/$view[0]" . '.php';
// // break;
//
// // case 'flag5':
// // // source/store/cabinet/top/view/index.php
// // $file = "source/store/cabinet/top/view/$view[0]" . '.php';
// // break;
// // } // end switch
//
// // now that looks a lot cleaner!
// // anyhow, there are lots of ways to do this kind of thing and there is
// // no right or wrong way of doing it!
// // from here, you can branch out to display the view from
// // its own folder! for example:
// // first test to see if our levels of folders exist including its file
// if (file_exists($file))
// {
// require_once $file;
// }
// else
// {
// echo ("View file <b>$file</b> not found");
// }
// } // end if (strpos($view, '/'))
// } // end render()
// ***** END OF RENDER() *****
// you'll have to create a file called about.php and put it
// in the autoload directory!
// see my other tutorial called "how to autoload classes using SPL"
// do the same thing for the rest of these files:
// this is the manager telling the programmers to handover the task!
// maybe more appropriately the controller telling the view to
// display the model or data!
// the model is the the data to display: about.php
// the route for this method is: <a href="about">About</a>
public function about()
{
$this->base->render('about');
}
// the controller telling the view to display the model or data!
// the model is the the data to display: affiliate.php
// the route for this method is: <a href="affiliate">Afilliate</a>
public function affiliate()
{
$this->base->render('affiliate');
}
// the controller telling the view to display the model or data!
// the model is the the data to display: signup.php
// the route for this method is: <a href="signup">Signup</a>
public function signup()
{
$this->base->render('signup');
}
// DIDO!
// the route for this method is: <a href="login">Login</a>
public function login()
{
$this->base->render('login');
}
// DIDO!
// the route for this method is: <a href="profile">Profile</a>
public function profile()
{
$this->base->render('profile');
}
// this controller class Dispatcher's purpose is to dispatch controller
// to their proper destinations!
// it also displays static controller actions like about, affiliate, signup,
// login, profile, etc., on the spot without having to dispatch them anywhere!
// in other words, it calls render() directly on the spot without having
// external controller doing the job!
// by doing this (and by the look of this controller class 'Dispatcher'),
// it is very cluttered if you have lots of conttollers/actions!
// it will make this class very hard to navigate and debug!
// so static controller actions like about, affiliate, signup, etc., should
// be in external controller as well (as the following illustration shows!)
// so a better solution is to do what I'm attempting to do in the following,
// where you can create a controller method in your base/main
// application class similar to this example base class Base()!
// inside this main base class, you can create a controller method.
// this is my attempt to make this MVC application more robust and
// powerful by creating a controller instance and then call that
// external controller from within the inner controller (dispatcher/user) to
// execute that external controller (i.e., admin, cart, user, etc.)
// when a view sends a controller/action such as the route:
// <a href="user/signup">Signup</a>
// with 'user' being the controller and 'signup' being the action
// and it goes to splitUrl() and splitUrl() splits the url into pieces
// this might confuse some of you, in that, where 'user' is actually a
// method called user() instead of a controller class (as you'll see in a moment)
// this is because the objective of method user() is to create a controller class!
// so therefore, the route 'user/signup' can still be considered as the 'user'
// being the controller and 'signup' being the action
// remember the splitUrl() that exploded the url into pieces in class route?
// x1 is 'user' if the route is 'user/signup', 'user/logout', 'user/profile', etc.
// x2 is one of these: 'signup', 'logout', 'profile', etc.
// class route calls class Dispatcher() to dispatch to the proper controller!
// so in class route it splits 'user/signup' into pieces and then calls the
// method of the class Dispatcher() which looks like this:
// $base = new Base(); // assuming you have a main application class called Base()
// $dispatch = new Dispatcher();
// // so $method = 'user'
// $method = $this->base->x1; // with x1 being 'user', x2 = 'signup'
// this will call a method called 'user' of the Dispatcher class
// $dispatch->method;
// now inside that method user() you can call the controller like this:
// $x1 = $this->base->get('x1'); // 'user' is now a controller class
// $x2 = $this->base->get('x2'); // 'signup' is still an action or method
// now create the controller and call its action method
// $this->base->createController($x1)->$x2();
// remember that this class Dispatcher is a controller but this
// controller can have other external controller as well!
// sort of manager of managers: head manager having middle managers!
// I call them inner controller and external controller!
// some programmers call the two controller as 'frontcontroller' and
// 'controller', with 'frontcontroller' is analogous to my version
// called 'external controller' and 'controller' analogous to my
// version called inner controller('route' and 'dispatcher' classes).
// how you/I or anyone call them make no difference: all it matters is that
// there has to be two types of controller in order for it to work properly!
// put this method in your main application base class similar to class Base()
// so your main application base class should have a minimum of: a set(), get(),
// createController(), autoloading() using SPL, and render()
// public function createController($controller)
// {
// // here, you put all of your controller files in folder:
// // controller
//
// // this will load a controller class file like these:
//
// // controller/UserController.php
// // controller/AdminController.php
// // controller/CartController.php
// // controller/MediaController.php
//
// // make sure to name your external controller files accordingly!
// // e.g., UserController.php, AdminController.php, etc.
//
// // the reason that you append the word 'Controller' to your
// // external controller files is to differentiate them from
// // other classes, say, 'model' and 'view'!
//
// // then in the external class definition, you can name your
// // external controller classes accordingly, e.g.,
//
// // UserController, AdminController, CartController, etc.
//
// // you can convert the first letter in $controller to uppercase
// // using function ucfirst()
//
// $controller = ucfirst($controller);
//
// $file = "controller/$controller" . 'Controller' . '.php';
// if (file_exists($file))
// {
// require_once($file);
//
// // this is like: new AdminController, new CartController, etc ...
// $controllerObj = new $controller . 'Controller'();
//
// // return an instance of the controller class back to
// // the caller!
// // see an example controller class user below!
// return $controllerObj;
// }
// else
// {
// echo ("$controller" . 'Controller not found.');
// }
// ***** end of createController() *****
// right here, you can group all the action methods of class 'User'
// to call them: User->login, User->logout, User->profile, etc!
// don't mix up with function user() below with controller class
// 'User' later as in: createController('user')
// the call to createController('user') will create a controller class named
// 'User' or 'UserController' if you want to add 'Controller' to it!
// you can declare class 'UserController' to have a method called user()
// or any name you wish, but for this example I call it as user()
// the route for this method user() could be something like this:
// <a href="user/login/id/guest/vip">Login</a>
// or just:
// <a href="user/login">Login</a>
// which will get routed to class 'UserController' to have a method called user()
// <a href="user/logout/id/guest/vip">Logout</a>
// or just:
// <a href="user/logout">Logout</a>
// <a href="user/profile/id/guest/vip">Profile</a>
// <a href="user/admin_login/id/guest/vip">Admin Login</a>
// <a href="user/admin_logout/id/guest/vip">Admin Logout</a>
// <a href="user/admin_singup/id/guest/vip">Admin Signup</a>
// <a href="user/forgot/id/guest/vip">Forgot Password<></a>
// <a href="user/usernamecheck/id/guest/vip">Check Username</a>
// <a href="user/emailcheck/id/guest/vip">Check Email</a>
// and they all will come here to execute function user()!
// remember the splitUrl() that exploded the url into pieces in class route?
// x1 is 'user' if the route is 'user/signup', 'user/logout', 'user/profile', etc.
// x2 is one of these: 'signup', 'logout', 'profile', etc.
// so in the class route the code that calls 'user/signup' looks like this:
// $dispatch = new Dispatcher();
// $method = $this->base->x1; // assuming $base is an instance of class Base()
// this will call a method called 'user' of the Dispatcher class
// $dispatch->method;
public function user()
{
// x1 is 'user' if the route is 'user/login', 'user/logout', 'user/profile', etc.
// x2 is one of these: 'login', 'logout', 'profile', etc.
$x1 = $this->base->get('x1'); // assuming $base is an instance of class Base()
$x2 = $this->base->get('x2'); // assuming $base is an instance of class Base()
switch ($x2)
{
// the manager is asking the programmers to
// handover the tasks!
case 'login':
case 'logout':
case 'profile':
case 'admin_login':
case 'admin_logout':
case 'admin_singup':
case 'forgot':
case 'usernamecheck':
case 'emailcheck':
// right here, if any of the above case is met,
// it will come here to look for a specific
// controller action: $x2
// basically, $x2 is the action or controller
// method: login()
// we need to specify the external controller class as
// 'user' and it will route to that controller looking
// for an action method to execute!
// creating an external controller: 'user'
$this->base->createController('user')->$x2();
// you can pass the controller as a variable as well:
// $this->base->createController($x1)->$x2();
break;
default:
$this->init();
}
// as you can see, this is much more robust and powerful as it
// allows you to route to each controller class and to look for
// specific actions in that class!
// you can use this example method user() to do other external
// controller/action to make your MVC application more robust!
// notice that you can group these actions: about(), affiliate(),
// signup(), login(), profile() in a class of their own similar
// to the class 'User' and thus makes it more robust and powerful
// and less cluttered!
}
} // end class dispatcher
// as you can see, createController('external_controller_class') creates
// an instance of the external controller class!
// now you need to create those external controller classes!
// here is an example of the controller class User!
// this is the controller 'user'
// or if you want to differentiate your controller classes from
// other classes, you can append the word 'Controller' to the class
// name: 'UserController'
// see createController() example above for more detail!
// remember that these "external" controller classes are sort of middle managers,
// and in that, they tend to do a little more work than top managers.
// still, whether it is a top manager or middle manager, they should not
// do a lot of work!
// this means that these "external" controller classes should not do a
// lot of work either!
// all of the heavy work load is being done by the programmers (or the model).
// keep this analogy in mind as you work through the MVC pattern.
// there should not be any heavy work being done by the controller.
// these controller only need to know true or false. That's all! Nothing else!
// class User // UserController?
// {
// // public $base;
// // $this->base = new Base();
// // this is the action 'login'
// public function login()
// {
// // remember that this is the controller/manager
// // and the manager doesn't do any heavy work!
// // so the manager usually asks the workers to
// // do the actual heavy work!
// // so you should never have to do any heavy programming
// // in any of your "external" controller!
// // the controller should always asks the model to return
// // true or false whether the task is successfully
// // or not! that's all!
// // an example of that is the creation of class Base instance
// // above! as you can see, the controller/manager does
// // absolutely nothing in the form of heavy work!
// // the login credential: username and password
// // is available at the view via: HTTP REQUEST!
// // send it to the view: a login form!
// $this->base-render('login');
// }
// // this is the action "profile"
// public function Profile()
// {
// // remember that this is the controller/manager
// // and the manager doesn't do any heavy work!
// // so the manager usually asks the workers to
// // do the actual heavy work!
// // so you should never have to do any heavy programming
// // in any of your controller!
// // the controller should always asks the model to return
// // true or false whether the task is successfully
// // or not! that's all!
// // an example of that is the creation of class Base instance
// // above! as you can see, the controller/manager does
// // absolutely nothing in the form of heavy work!
// // send it to the view to display the profile!
// $this->base-render('profile');
// }
// this is the controlller
// if you want to differentiate your controller classes from
// other classes, you can append the word 'Controller' to the class
// name: 'UserController'
// see createController() example above for more detail!
// class SomeOtherController
// {
// public $base = array();
// $this->base = new Base();
// // this is the action "someaction"
// public function SomeAction()
// {
// // remember that this is the controller/manager
// // and the manager doesn't do any heavy work!
// // so the manager usually asks the workers to
// // do the actual heavy work!
// // so you should never have to do any heavy programming
// // in any of your controller!
// // the controller should always asks the model to return
// // true or false whether the task is successfully
// // or not! that's all!
// // an example of that is the creation of class Base instance
// // above! as you can see, the controller/manager does
// // absolutely nothing in the form of heavy work!
// // send it to the view to display the someview!
// $this->base-render('someview');
// }
?>
Notice that the manager does very little! All of the heavy work load is being done by the programmers.
Keep this analogy in mind as you work through the MVC pattern. There should not be any heavy work being done by the controller. The controller only need to know true or false. That's all! Nothing else!
For example, if you're programming a registration or login application, the model or model need to return only true or false if a user is successfully registered or logged in. Likewise, with other model, they need to return only true or false to the controller and nothing else.
For example, if a model is retrieving a bunch of products to be used in a catalog display in a view, the model can return true if the products are successfully retrieved from the database or false otherwise. For example:
<?php
/**
* retrieve the products from the database
*/
class Product
{
// constructor
public function __construct()
{
// constructor code logic);
}
// get the product
public function getProduct()
{
// code logic
// query the database: SELECT * FROM Product
// return the product to the controller as an array!
// $catalog = SELECT * FROM Product ....
// if $catalog)
// {
// $this->base->set('catalog', $catalog);
// return $catalog;
// }
}
}
// then in your controller you can do this:
// $product = new Product();
// $catalog = $product->getProduct();
// if $catalog)
// {
// $this->base->render('catalog');
// }
?>
In getProduct(), you need to retrieve the products from the database and return the products accordingly so that in the controller, you can just test to see if it returns any product or null. True or false!
In the controller, all it needs to be done is instantiating the model: $product = new Product().
$model = $product->getProduct().
Now the controller or manager can handover the product to the view.
You can send it to the view via a render() method: $this->base->render('catalog', ['model' => $model]).
Remember that the second argument of render() is an array; and therefore, you can send one model or multiple models to the view using the array to hold all the models. The trick is to test for each array element inside your view file 'catalog.php' and pick them out one by one using the array key/value pairs.
How you implement the second argument logic is up to you. One way to do it, is to set the properties inside your render(). See the following description on how to do it.
As stated above is to query the database for each model and store your models in the array using the key/value pairs to hold your models and then send the array to the view. In other words, gather all of your models [from the database or from other sources] and then put them in the array and then send that array as the second argument of the render() to the view.
For example:
$this->base->render('catalog', ['product' => $product, 'credential' => $credential, 'catalog' => $catalog, 'sale' => $sale, 'employee' => $employee'])
Make note that the second argument of render() is an array containing multiple models that are being sent to the view.
Now you need to implement the second argument logic inside your render() that sends the models or the array key/value pairs to the view. You can set the properties inside your render() as well. See the following render() example on how to do it.
<?php
/**
* here is a very brief example of the second argument implementation of render()
* for a more extended example of render() see an earlier example of render()
*
* note also that set(), like render(), is a method of the class Base
*/
// render() is a method of the class Base
public function render($view, $model == null)
{
// code logic
if (!$model == null)
{
// if the caller of this render() sends in a model, we'll set the key/value pairs
foreach ($model as $key => $value)
{
// $this->set() refers to class Base's set() method
// here, we're setting class Base properties using array key/value pairs
$this->set($key, $value);
}
}
// more render() code logic handling/implementing $view
if (strpos($view, '/')
{
$view = explode('/', $view);
// now $view is an array of two elements: a folder and a file
// $view[0] = 'view', $view[1] = 'index'
// $view[0] = 'affiliate', $view[1] = 'index'
// $view[0] = 'about', $view[1] = 'index'
// $view[0] = 'profile', $view[1] = 'index'
// for a more extended render() code logic, see a render() code example shown earlier
}
} // end function render()
?>
The easiest way to send models to the view is to set the properties inside your render() as shown above. You can also set the properties in the model right after querying the database [as appose to setting it inside the render() as shown above]. Inside your model class code logic, you need to set the properties of the model like the following assuming '$base' is the instance of the base class Base:
$this->base->set('model', $model);
Now the above line sets the property called 'model' to your base controller class similar to class Base() in this example.
And likewise, for the rest of the models:
$this->base->set('product', $product);
$this->base->set('credential', $credential);
$this->base->set('catalog', $catalog);
$this->base->set('sale', $sale);
$this->base->set('employee', $employee);
Setting properties in the model can be more efficient and robust and you can set lots of properties for your model.
Now after using set() above, the controller or manager can just handover the product to the view: render('catalog') without having to worry about the model.
Now inside the catalog view file 'catalog.php', you can retrieve that property like this: $catalog = $this->base->get('model').
Display the catalog. For example, inside the view 'catalog.php':
foreach ($catalog as $key => $value)
$key should be a product id and $value should be an array holding the product object: id, name, price, description, image, etc.
How you implement your view's render() is up to you. You can make improvement to the barebone render() code example just shown above and also the one shown earlier (as well) to make it more robust, like handling multiple themes and files.
Inside the barebone render() (above and earlier) you can make it more robust and powerful by branching out to display snippets of view like sidebars flash display, ad flash display, and other content displays. See earlier code example for guidance.
Note that it is a good idea to specify the second argument of render() as an array: render($view, $template = array())
Please use the very popular shorthand array: render($view, $template = []).
This way, you can send all kinds of content to the view!
Note that you don't need more than two arguments in render() as the second argument handles all kinds of content to be sent to the view.
You can specify the second argument as an optional argument as well by doing this: render($view, $template[] = null).
By doing that you can send only the "static" view page that are simple view like about, contact, profile, etc, without using the second argument. For example:
$this->base->render('about'); // this will render the "static" view/about.php page
$this->base->render('contact'); // this will render the "static" view/contact.php page
$this->base->render('profile'); // this will render the "static" view/profile.php page
As stated above, there should not be any heavy work being done by the controller. All of the heavy work load should be done by the model.
The model should be autoloaded using SPL autoload and are grouped in their own folders. Likewise, for the view and controller, they should be grouped in their own folders and autoloading them accordingly (specifically the controller -- view are loaded and included in the render() already). See my other tutorials called "how to autoload classes using SPL."
To learn more about MVC pattern, please check out the Internet by Googling the term MVC or Model View Controller.
For a starter, here is a list of very good introductory tutorials on the Web that I found to be very good tutorials:
The MVC Pattern: PHP, MVC and Best Practices The MVC Pattern and PHP, Part 1 The MVC Pattern and PHP, Part 2 The MVC Pattern: An Introduction to the Front Controller Pattern, Part 1 The MVC Pattern: An Introduction to the Front Controller Pattern, Part 2For a more advanced pattern methodology, please check out MVVM (Model-View-ViewModel)
Advanced Pattern: The advantages of MVVM over MVCThere you have it: a very brief but useful introduction to MVC pattern.
You should be able to use this MVC pattern tutorial and build your very own sophisticated applications--large or small. From here, the possibilities are endless!
Have fun programming and don't forget to thank me later!
The following are just bonus MVC materials to help you understand the MVC concept further.
The following materials are taken from the tutorials mentioned in the links earlier.
It is possible to write a web application in PHP whose architecture is based on the MVC pattern. Let's start with a generic bare bones concept example.
Remember that there are three parts: M-V-C?
We'll start with 'M', which is the model.
The model is the data. If you recall from my tutorial earlier, the model is the programmers and the programmers do all the heavy work in manipulating the data. So data equals programmers. Keep that in mind!
What are we really trying to do here?
If you look in the code example below, it says $this->string = "MVC + PHP = Awesome!".
$this->string is a variable to hold data, hence model is all about data.
And the actual data is: "MVC + PHP = Awesome!".
Do you get the hang of it?
This example shows a very simple case of handling data. In most cases, you'll have to query the database to get the model. Yes, that is not a misstatement. In an MVC talk, it's a 'model' but in a human talk, it's a 'data'. Get used to talking about model being the data from now on!
<?php
class Model
{
public $string;
public function __construct()
{
// get the model. most cases, you'll do some database queries
// $this->string = 'SELECT * FROM someTable'
// remember that all the heavy work are being done right here in the model?
$this->string = "MVC + PHP = Awesome!";
}
}
?>
This is the view or 'V'.
The view is the display - showing the model to the user. Take a look at the function output(). It's main purpose is to output the data to the user. I really mean it outputs the model to the user.
Before it can output the model to the user, it has to get it first by way of the constructor. In other words, the model is passed to the view via the constructor.
Since the view needs the instruction from the controller as well, it also needs to pass the controller to the view as well.
Remember the controller? Or a manager? Maybe a manager who coordinates the tasks, perhaps?
<?php
class View
{
private $model; // this variable $model is for holding an instance of the class Model
// as you may well know that once you have an instance of a class (Model),
// you can get access to its attributes!
// in this case, we can get the class Model's data: MVC + PHP = Awesome!
private $controller; // this variable $controller is for holding an instance of the class Controller
// again, once you have an instance of a class (Controller),
// you can get access to its attributes!
// here in the constructor is where you can pass instances of the classes
// to allow you to get access to their attributes!
// so this constructor (or this View class) is being called like the following:
// the following code should be in the "external" controller
// notice that the controller does very little work!
// all of the works are being done by the model!
// $model = new Model();
// $controller = new Controller($model); // a manager/controller asking the model for the data
// $view = new View($controller, $model);
// echo $view->output();
public function __construct($controller, $model)
{
$this->controller = $controller;
$this->model = $model;
}
// now inside this class View is where we have instances of the classes,
// and we can get access to their attributes and display to users/viewers!
// as you can see from inside the method output(), once we have instances
// of the classes, we can get their attributes, i.e., $this->model->string
public function output()
{
// right here where it is very tricky!
// it tries to get the string: MVC + PHP = Awesome!" from the model in
class Model shown earlier!
$this->model refers to the private variable $model above!
->string refers to a public variable in class Model shown earlier!
basically, it returns the string: "MVC + PHP = Awesome!"
return "<p>" . $this->model->string . "</p>";
}
}
?>
Here is the controller or 'C'.
Remember the controller? Or a manager? Maybe a manager who coordinates the tasks, perhaps?
Remember that a manager/controller does very little work. The heavy work are being done in the model.
So what sort of tasks are to be performed by the controller?
If you look at the code below, all it does is taking a model and does nothing!
This is a manager asking a programmer to hand over the task so that a manager can give it to a customer/view.
If you recall my tutorial earlier, I stated that there are two controller: inner controller and external controller - sort of top manager and middle manager interacting with one another to complete the tasks.
This controller, you can say that it is the top manager. Later on, you'll see another controller or middle manager who responses to this top manager and then that middle manager coordinates the final tasks to tell the view to display the model to the user.
<?php
class Controller
{
private $model; // this variable $model is for holding an instance of the class Model
// this is a manager asking a programmer to hand over the task so that
// a manager can give it to a customer/view
// in most cases, you'll do just a little bit more to ask for the data from
// the model and then handing it over to the view to be displayed
// the main thing to remember is that you have to create some variables
// like $model declared above to hold some model!
// most cases, you'll declare lots of variables to hold model as most
// cases you have lots and lots of model to handle in this class Controller!
// and in most cases, you'll need to have some controller methods, i.e., signup,
// login, logout, about, etc., to return the external controller instances.
// see controller method click() later on for an example!
public function __construct($model)
{
$this->model = $model;
}
}
?>
We have our project started with some very basic classes for each part of the pattern. Now we need to set up the relationships between them.
This is the middle manager who coordinates the final tasks.
As you can see, neither the top manager nor the middle manager does any work at all. All they do is just coordinate the final task.
<?php
$model = new Model();
$controller = new Controller($model);
$view = new View($controller, $model);
echo $view->output();
?>
Here is their explanation of the code above:
As you can see in the example above, we don't have any Controller-specific functionality because we don't have any user interactions defined with our application. The View holds all of the functionality as the example is purely for display purposes.
Let's now expand the example to show how we would add functionality to the controller, thereby adding interactivity to the application:
<?php
class Model
{
public $string;
public function __construct()
{
// get the model. most cases, you'll do some database queries
// $this->string = 'SELECT * FROM someTable'
$this->string = "MVC + PHP = Awesome, click here!!";
}
}
?>
<?php
class View
{
private $model;
private $controller;
public function __construct($controller, $model)
{
$this->controller = $controller;
$this->model = $model;
}
public function output()
{
// right here, it returns an anchor link to the caller!
// remember what $this->model->string returns?
// a hint: "MVC + PHP = Awesome, click here!!"
// basically, when you click on the anchor link it will call a
// function named click()
// action=click refers to a controller function named 'click'
// see class Controller with function named 'click' below!
// you can format your anchor link like this as well and you can
// include as many GET parameters as you want using '&'. for example:
// '<a href="http://www.example.com/index.php?action=click¶m1=value1">' .
// $this->model->string . "</a>"
return '<p><a href="mvc.php?action=click">' . $this->model->string . "</a></p>";
}
}
?>
<?php
class Controller
{
private $model;
public function __construct($model)
{
$this->model = $model;
}
public function click()
{
// this one statement below breaks the MVC rule by having a controller
// performing a model's task! this is not a good idea!
// we should not be doing data calculation and manipulation in here!
// we can ask a model to return a data and assign that data to: $this->model->string
// a lot of programmers are tempted to do exactly like this one by querying
// data from the databse and assign that data to: $this->model->string
// avoid doing a short cut like here and always adhere to the MVC rule
// you can declare some variables to hold the model and send those model
// to their proper view
$this->model->string = "Updated Data, thanks to MVC and PHP!";
}
}
?>
We've enhanced the application with some basic functionality. Setting up the relationship between our components now looks like this:
The following code is the main base application and it is analogous to a
class called Base() in my MVC example shown earlier.
It is the main application base class similar to the example class Base()
shown in my other tutorial called 'How to autoload classes using SPL'.
See class Dispatcher, particularly the method render() about explanation
on Base() class.
In other words, put the following code in your main application base class similar
to class Base() shown in my other tutorial called 'How to autoload classes using SPL'.
<?php
$model = new Model();
// this is similar to a code that creates a controller class: see createController()
$controller = new Controller($model);
$view = new View($controller, $model);
if (isset($_GET['action']) && !empty($_GET['action']))
{
// once you instantiated a controller class, you can use that
// controller instance ($controller->) to call its action method via: $_GET['action']
// so if you have a controller class called CartController, and its
// action method called addToCart(), then the code below would be:
// CartController->addToCart()
// provided that you change the action method $_GET['action']
// to $_GET['addtocart']
// this is similar to a code that creates a controller class: see createController()
// and it looks something like this:
// creating an external controller: 'user'
// $this->base->createController('user')->$x2();
// you can pass the controller as a variable as well:
// $this->base->createController($x1)->$x2();
// notice that: $this->base->createController($x1) being the $controller->
// and $x2() being the $_GET['action']()
// notice that the {} wrapping around $_GET is analogous to 'echo'
$controller->{$_GET['action']}();
}
// this will echo out an anchor link:
// <a href="mvc.php?action=click">MVC + PHP = Awesome, click here!!</a>
// now all you have to do is click on the anchor link to see the effect!
echo $view->output();
?>
Run the code and when you click on the link you'll be able to see the string change its data.
Conclusion
We've covered the basic theory behind the MVC pattern and have produced a very basic MVC application, but we still have a long way to go before we get into any nitty-gritty functionality.
This concludes MVC extra bonus materials!
access control: public, protected, and privatepublic, protected, and private are visibility clauses (similar to static and final). A visibility clause is a term used to describe the access control in certain part of the code. It's like a key to a toolbox where you are allowed to use certain tools for certain projects only if you have the key to open it. It is restricted to use certain tools. So you can't just go grab the tools and use freely; you have to have certain keys to open the toolbox and use the tools.
In programming, we have visisibility clauses or visibility controls to allow you to restrict certain part of the code to be accessible to certain programs.
Visisibility clauses or visibility controls allow certain part of code to be protected from outside abuses. Visisibility clause or access control is about controlling visibility of the methods and variables from outside classes usage. The visibility of the code elements are determined by their access control specifications or clauses: public, protected, and private.
Note: the term visisibility clause or access control mean the same thing and both are being used interchangibly.
protect" a method or variable from unauthorize references, you use the three levels of access control visibility: public, protected, and private.
A class is like an island onto itself where only people on the island can get access to the resources residing on that island. Because of this inaccessibility that a method of distinguishing who is allowed to get on and who is not allowed to get on -- and what level of restrictions certain methods and variables are placed on -- was developed.
The three-level of restrictions was developed to allow access control of the methods and variables.
Note: Visibility access control only concern with methods and variables and nothing else. Variables sometimes referred to as property variables or just plainly properties. So keep this in mind as you go through the descriptons:
methods and variables declared as public can be accessed everywhere.methods and variables declared as protected can be accessed only within the class itself and by classes derived from that class.methods and variables declared as private may only be accessed by the class that defines the methods and variables. In other words, ONLY the class that defines the private methods and variables can access these private methods and variables [that they defined themselves].
All other classes cannot access these private methods and variables [of another class or classes]. They can ONLY access their own private methods and variables.
methods and variables declared without any explicit visibility keyword are defined as public.Before we get into the main visibility access control: public, protected, and private, let's get this one nagging issue out of the way that seems to get a lot of people confused, and that is, the use of keyword var. For example:
<?php
class MyClass
{
/** declaring MyClass' properties: **/
/**
* as you can see below, we declare a property called $make as 'public'
* using the keyword 'var'.
* this is the same as declaring: public $make
*/
var $make; // declaring a property as 'public'
// for non-public properties, you use the appropriate clause, i.e., protected.
protected $model;
// for non-public properties, you use the appropriate clause, i.e., private.
private $color;
}
?>
The keyword var was the original design to signify the property as a public variable. So instead of having to specifically declaring a property using the keyword public, all we had to do was using the keyword var followed by the variable name and we had a public property variable. That was in the old days!
Then the folks at PHP decided to get rid of the old legacy mistake and instituted the proper way of doing things by replacing the keyword var with the keyword public starting in PHP 5.0. Then an uproar erupted and created a lot of confusion. It lasted for a couple of versions until it was too much of a headache to bear and they decided to put back the old legacy style by re-instituting the keyword var to its original style starting in PHP 5.3.
Since version 5.3 and onward, you can actually use either of the two keywords and they will all work just fine. However, they really stress/encourage all programmers to use keyword public and discourage the use of keyword var.
Visibility Access Control: Public, Protected, and PrivateLet's see how to use the visibility access control: public, protected, and private. For example:
<?php
/**
* declaring class Vehicle's properties only -- no methods
*/
class Vehicle
{
// declaring class Vehicle's properties:
public $make; // declaring a property as 'public'
protected $model; // declaring a property as 'protected'
private $color; // declaring a property as 'private'
}
?>
Now to see the effect of the visibility clauses in action, consider this:
<?php
/**
* now we're creating another class outside of class Vehicle.
* this class will try to get through class Vehicle's visibility control.
* let's see if this class can get through class Vehicle's visibility control.
*/
class Ford
{
// creating an instance of class Vehicle:
$obj = new Vehicle();
// now try to get through class Vehicle's visibility control.
/**
* this reference is fine because the property is declared as
* 'public'. so class Vehicle allows class Ford to use its property.
*/
$obj->make = 'Ford';
/**
* this reference will cause a 'fatal error' because the property is declared as
* 'protected'. so class Vehicle didn't allow class Ford to use its property.
*/
$obj->model = 'F150';
/**
* this reference will cause a 'fatal error' because the property is declared as
* 'private'. so class Vehicle didn't allow class Ford to use its property.
*/
$obj->color = 'grey';
}
?>
As you can see, declaring methods and properties as protected and private restricts outside classes like Ford from using its properties.
methods and property variables. For example:
<?php
/**
* now we're adding methods to class Vehicle.
*/
class Vehicle
{
// declaring class Vehicle's properties:
public $make; // declaring a property as 'public'
protected $model; // declaring a property as 'protected'
private $color; // declaring a property as 'private'
/**
* declaring class Vehicle's method as 'public'
* notice that declaring a method without the visibility clause has
* the same effect as 'public'. so the 'public' clause can be omitted!
*/
public function setMake($make)
{
// assigning a value to class Vehicle's property
$this->make = $make;
}
// declaring class Vehicle's method as 'protected'
protected function setModel($model)
{
// assigning a value to class Vehicle's property
$this->model = $model;
}
// again, declaring class Vehicle's method as 'private'
private function setColor($color)
{
// assigning a value to class Vehicle's property
$this->color = $color;
}
}
?>
Now to see the effect of the visibility clauses in action, consider this:
<?php
/**
* now we're creating another class outside of class Vehicle.
* this class will try to get through class Vehicle's visibility control.
* let's see if this class can get through class Vehicle's visibility control.
*/
class Audi
{
// creating an instance of class Vehicle:
$obj = new Vehicle();
// now try to get through class Vehicle's visibility control.
/**
* this reference is fine because method setMake() was declared as
* 'public'. so class Vehicle allows class Audi to use its method.
*/
$obj->setMake('Audi');
/**
* this reference will cause a 'fatal error' because setModel() was declared as
* 'protected'. so class Vehicle didn't allow class Audi to use its method.
*/
$obj->setModel('A6');
/**
* this reference will cause a 'fatal error' because setColor() was declared as
* 'private'. likewise, class Vehicle didn't allow class Audi to use its method.
*/
$obj->setColor('grey');
}
?>
As you can see, declaring methods and properties as protected and private can be accessed only from within the class that those methods and properties are defined.
protected properties or methods can be accessed within the class and by classes derived from that class'. What does that mean?
Let's take a look at the same class definition Vehicle but this time we will extend this Vehicle class further and see if child classes can get access to class Vehicle's visibility control:
<?php
class Vehicle
{
/**
* declaring class Vehicle's properties as private:
* notice that these two 'private' properties can be accessed only from inside
* this Vehicle class. classes that extends from Vehicle cannot access these
* two private properties.
*/
private $price;
private $tax;
/**
* declaring class Vehicle's constructor as 'public'
* notice that declaring a method/constructor without the visibility clause
* has the same effect as 'public'. so the 'public' clause can be omitted!
*/
public function __construct($price, $taxRate)
{
/**
* assigning values to class Vehicle's properties
* 'private' properties can be accessed only from inside this Vehicle class
*/
$this->price = $price;
$this->tax = $taxRate;
}
/**
* if calculateTax() was declared as 'private' no child class can access this
* private method. the only method that can access this private method is from inside
* the constructor using $this, for example: $this->calculateTax()
*
* let's be clear about this: ONLY if calculateTax() is declared as 'private'
*
* let's clarify that statement earlier a little bit:
* 'the only method that can access this private method is from inside the constructor'
*
* that statement is only true if this Vehicle class has only the constructor method as
* it stands right now.
* if there are more methods to be had, regardless of their visibility clause,
* then they all can access to these private properties as well as other private methods
* of class Vehicle. so 'private' means ONLY within the class itself and not outside of
* the class. this means that any method within the class can access 'private' properties
* and methods declared within the class.
* so make note of that!
*
* this means that no other class or classes even child class or classes of Vehicle can
* get access to class Vehicle's private properties and methods.
*
* however, calculateTax() is declared as "protected" and therefore child classes of
* Vehicle can get access to calculateTax() just fine!
*
* did you remember a phrase that goes like this [?]:
* 'protected can be accessed only within the class itself and by classes derived from
* that class'.
*
* this is exactly what that phrase means!
*
* here is the 'protected' method calculateTax()
*/
protected function calculateTax()
{
/**
* now since this method is declared as 'protected' child classes that extend
* from this parent class Vehicle can get access to this 'protected' method.
* no other classes can get access to this 'protected' method.
*/
// getting a tax
$tax = $this->$price x $this->$taxRate;
return $tax;
}
}
?>
Now to see the effect of the protected or private visibility clause in action, consider this:
<?php
class Ford extends Vehicle
{
public function getTax()
{
// getting a tax from parent class Vehicle
// calling a protected method, is it legal?
// see below and an explanation later as well!
$tax = $this->calculateTax();
return $tax;
/**
* the 'protected' rule: child classes that extend from a parent class with
* methods declared as 'protected' can get access to those 'protected methods.
* no other classes can get access to those 'protected' methods.
*/
}
}
?>
Now to see the effect of the visibility clauses in action in child class Ford, consider this:
<?php
/**
* now we're creating another class Audi outside of class Vehicle and Ford.
* this class Audi will try to get through Vehicle's and Ford's visibility controls.
* let's see if Audi can get through class Vehicle's and Ford's visibility controls.
*/
class Audi
{
// creating an instance of class Ford which extends Vehicle:
$obj = new Ford('25000', '0.07');
/** now try to get through class Ford's and Vehicle's visibility controls. **/
/**
* calling $obj->getTax() is OK because Ford's method getTax() was declared as
* 'public'. so class Ford allows class Audi to use its method getTax().
* now, in turn, getTax() calls calculateTax() (which is declared as 'protected') from
* within the derived class Ford.
*
* a public method getTax() calls a protected method calculateTax()!
*
* is it legal for a public method to call a protected method?
*
* did you remember a phrase that goes like this [?]:
* 'protected can be accessed only within the class itself and by classes derived from
* that class'.
*
* '.... by classes derived from that class' means Ford derived from Vehicle.
*
* getTax() calls calculateTax() from inside class Ford.
* class Ford is a derived class from Vehicle.
*
* as you can see, it is OK for a public method to call a protected method from
* inside the derived class, in this case, Ford.
*/
$obj->getTax(); // calling $obj->getTax() is OK because getTax() is 'public'
}
?>
Let's re-cap what the three visibility control are:
public just the word implies, it is open to the public and anybody can get access to these public methods and properties.
protected just like the word implies, it is protected within the family and relative circle, and others outside of the family and relative circle cannot get accessed to the protected methods and properties. This means that child class (or classes) methods and properties declaring as public can get access to parent class methods and properties declared as protected.
private just like the word implies, it is a private matter/affair and it is not open to the public or to their own descendant classes either. This is very strict even their own relatives and descendants can't even get accessed to methods and properties of a private class.
methods and properties inside a private class can only be accessed from inside that private class by their own member methods and properties. Child class or classes of the private class cannot get accessed to their own parent's methods and properties. That is very harsh!
So the key to remembering these three visibility controls is that, just think of them in term of real life examples like family and relatives and strangers and associate each scenario accordingly.
Another point is, to memorize protected first and leave the other two alone.
In other words, don't try to memorize the other two and only try to memorize protected very good. That way, you don't get them mixed up so easily.
Just think that protected is a protection within the family and relative, and descendants cycle and anybody outside of the cycle cannot get accessed to protected methods and properties.
Magic methods are special methods which override PHP's default's action when certain actions are performed on an object.
All methods names starting with __ are reserved by PHP. Therefore, it is not recommended to use such method names unless overriding PHP's behavior.
In other words, DO NOT use __ (that is double underscores) for your own variables, methods, or class names
For example, these are illegal: $__myVar, __MyMethod(), class __Connection.
I repeat: __ is reserved by PHP.
The following method names are considered magical: __get(), __set(), __isset(), __unset(), __construct(), __destruct(), __call(), __callStatic(), __sleep(), __wakeup(), __serialize(), __unserialize(), __toString(), __invoke(), __set_state(), __clone(), and __debugInfo().
Notice that they all use the __ (double underscores).
All magic methods, with the exception of __construct(), __destruct(), and __clone(), must be declared as public, otherwise an E_WARNING is emitted.
Magic methods in PHP provide mean to dynamically create properties and methods. These dynamic properties and methods are processed via magic methods one can establish in a class for various action types.
All magic methods are invoked automatically by PHP when interacting with properties or methods that have not been declared or are not visible in the current scope.
Let's clarify that last two paragraphs (or statements) above and explain it further.
Magic methods are being used frequently to overcome restrictions imposed by programming rules (or programming paradym) -- rules such as you can't access protected or private members variables and methods from outside the current scope or class. This is called access controll and is universally understood by programmers.
If you don't understand access control you can read my other tutorial on this website and the tutorial is called public verses protected verses private.
There are two use cases for magic methods:
1. Magic methods are frequently used to overcome the access control restriction to allow programmers to access protected and private variables and methods without running into the programming paradym restriction.
2. Another use for the magic methods is to create property variables 'on the fly' when you need new properties to be created on the fly or just-in-time.
Let's explain the second case first and then come back to explain the first case later.
When you create a class you have to declare properties and methods in your class, but that is not always feasible and it cluttered the space in your class. To solve this clutter issue and many other cases involving properties you are allowed to create properties 'on the fly'.
Let's say you created a class that contains properties and methods but later you need other properties for that class, you have two choices:
One, go back to your class and add your new properties to your class and you're good to go.
As you can see, it takes a lot of effort to do that because you have to track down your class (among many classes) and open that class and modify your code in that class.
That seems a lot of work just to add properties to your class.
Two, you can use magic methods to do your dirty work for you.
Magic methods make it easier to add properties to your (old) class by just using the magic methods to do the dirty work for you.
All you have to do is creating a magic method and when you have your (new) properties you can just refer to (or interacting with) those properties and PHP will call that magic for you automatically just like when you create an object of a class and PHP automatically calls the constructor for you.
Yes, that is right: __constructor() is a magic method and is invoked automatically by PHP.
Now that the second case was briefly explained, let's explain the first case in detail next.
That is not really true at all. It will illustrate for both the first and second case together in extended detail.
In actuality, the following actually illustrates both use cases in great detail: inaccessible protected or private and non-existing properties.
As you read the detail description below you'll see that there are four magic methods being illustrated: : __set(), __get(), __isset(), __unset().
These four magic methods are called or invoked automatically by PHP. However, PHP only calls or invokes these magic methods in the same manner when PHP calls or invokes the famous magic method __construct().
In other words, PHP only invokes these magic methods but does nothing else. You have to provide code inside these magic method for PHP to execute.
Just like you have to write code inside your __construct() magic method, you also have to write code inside your four magic methods as well.
Whatever you write inside these magic methods PHP will execute them for you in the same manner when you write code inside your constructor.
The kind of code you write in your constructor depends on the logic of your application; and likewise, the kind of code you write in your four magic methods depends on the logic of your application as well.
Let's take one magic method to illustrate the point stated above: __set().
__set() is run or invoked automatically when you attempt to write or assign data to inaccessible (protected or private) or non-existing properties. In other words, when you attempt to write to a non-existing or inaccessible property, PHP calls __set() method automatically.
You already know that in actuality you can't write data to protected or private or non-existing properties. You just can't!
Magic method __set() allows you to write data to protected or private or non-existing properties and therefore circumvent the restriction imposed by programming language paradym.
The access controll is the programming language paradym and is universally understood by programmers.
You can't write data to protected or private or non-existing properties. You just can't!
And you can't create properties 'on the fly' if you need new propterties. You just can't!
You have to use magic methods to do your dirty work.
The most popular magic methods frequently used by programmers are: __set(), __get(), __isset(), __unset() and have the following signature heading.
Let's see some examples on how to use magic methods to do your dirty work.
<?php
/**
* __set() is run when writing data to inaccessible (protected or private) or non-existing properties.
*
* In other words, when you attempt to write to a non-existing or inaccessible property, PHP calls __set() method automatically.
*
* As stated earlier, you have to write the code logic inside this __set() method for PHP to execute it for you.
* What kind of code is needed inside this __set() method ?
*
* Well, as the name implies, __set() is supposed to set or assign a value to a property (protected or private properties in this case).
*
* As you can see, you can now assign a value to a protected or private property from outside the scope using __set().
*
* For example, in a later example, you'll see the code that attempts to assign (or write) a value
* to a non-existence property like this:
*
* $obj->propA = 100;
*
* Remember that without magic method __set() you can't assign a value to a protected or private property outside of the scope.
*
* Creating an instance of MyClass and call it as $obj and using $obj outside of the scope is illegal without using __set().
*
* $obj is an instance of class MyClass, propA was a non-existence property,
* while 100 is an arbitrary value to write to the previously non-declared, non-existence property propA.
*
* The syntax signature looks like the following:
*
* public __set(string $name, mixed $value): void
*
* The $name argument is the name of the property being interacted with (i.e., propA).
* The __set() method's $value argument specifies the value the $name'ed property
* should be set to (i.e., 100).
*
* So it seems that __set() will contain the code similar to the following:
*
* public __set($name, $value)
* {
* // $obj->propA = 100
* $this->$name = $value; // make note: it is $this->$name and not $this->name
* }
*
* Make note: propA did not previously exist when class MyClass was created; however, after the
* referenced above that triggered a call to __set($name, $value), then propA magically exists;
* and therefore later, we can access it or read it using the code like the following:
*
* $var = $obj->propA; // see __get() example later
*
* As stated earlier, you have to write the code logic inside your magic method __get() for PHP to execute it for you.
*
* You'll see that class MyClass did not declare a property called propA at all, so propA was a
* non-existence property to begin with.
*
* Only after when you attempted to write to propA by specifying propA as a property
* of class MyClass that propA existed. Very magic, indeed!!!
*
* But in actuality, propA didn't exist at all before the reference.
* See the next code illustration signature below (in the __set() example).
*/
public __set(string $name, mixed $value): void
?>
<?php
/**
* __get() is utilized for reading data from inaccessible (protected or private) or non-existing properties
*
* In other words, when you attempt to access a property that doesn't exist or a property that is
* in-accessible, e.g., private or protected property,
* PHP automatically calls the __get() method automatically.
*
* For example, in some later examples, you'll see the code that attempts to access (or read) a value
* stored in propA property like this:
*
* Make note: propA is now exists only after the referenced that triggered a call to __set(), and then
* propA magically exists; and therefore, we can access it or read it using the code like the following:
*
* $var = $obj->propA;
*
* $obj is an instance of class MyClass, propA is now an existence property that contains some value,
* while $var is just an arbitrary variable to hold the value of the now existence property propA.
*
* You'll see that class MyClass did not declare a property called propA, so propA was a
* non-existence property to begin with.
*
* Now it exists only after when you attempt to write to propA by specifying propA as a property of class MyClass.
* But in actuality, propA didn't exist at all before the reference.
* See the next code illustration signature below (in the __get() example).
*/
public __get(string $name): mixed
?>
<?php
/**
* __isset() is triggered by calling isset() or empty() on inaccessible (protected or private) or
* non-existing properties.
*
* In other words, __isset() is another magic method that (we) programmers use when we want to check
* the access of any non-existent or inaccessible properties of a class object.
* To call the __isset() magic method, we have to call the __isset() with the inaccessible or
* non-defined properties as its parameter.
*
* It is automatically invoked to check whether a needed object property is set or not.
*
* For example, consider the following code illustration for a better visualization.
*
* <?php
* class Example
* {
* private $data = array();
*
* public function __isset($n)
* {
* echo "__isset() magic method invoked.";
* return isset($this->data[$n]);
* }
* }
*
* // now create an instance of the class
* $obj2 = new Example();
*
* // now let's trigger a call to the magic __isset($n) above
* echo isset($obj2->empid); // notice that empid is a non-existence property
*
* As you can see, the program wants to access the inaccessible object property which
* is not defined as a part of the Example class.
*
* The isset() method takes the 'empid' inaccessible variable as a parameter for
* checking the existence of the object property.
*
* See the follwoing code illustration signature.
* ?>
*/
public __isset(string $name): bool
?>
<?php
/**
* __unset() is invoked when unset() is used on inaccessible (protected or private) or non-existing properties.
*
* In other words, __unset() is another magic method that is invoked automatically for destroying a variable
* and freeing up memory space.
*
* When __isset() is used for checking whether a variable exists or not,
* the __unset() simply destroys a variable when used on non-existing or inaccessible properties.
*
* Consider the following code illustration:
*
* <?php
* class Example
* {
* private $dat = array();
*
* public function __isset($n)
* {
* return isset($this->dat[$n]);
* }
*
* public function __unset($n)
* {
* echo "__unset() magic method invoked.";
* unset($this->dat[$n]);
* }
* }
*
* // now let's create an instance of the class
* $obj2 = new Example();
*
* // this will trigger a call to __set()
* $obj2->a = 62;
*
* // this will trigger a call to __isset()
* if (isset($obj2->a))
* {
* // and this one will trigger a call to __unset()
* unset($obj2->a);
*
* // now property a is no longer exists because it was unsetted or destroyed!
* echo "Destroyed obj2 -> a ";
* }
*
* See the follwoing code illustration signature.
* ?>
*/
public __unset(string $name): void
?>
Let's see some more examples usage of these four magic methods. For example:
<?php
/**
* magic methods example
*
* The purpose or goal of creating this class and overriding these four magic methods is
* to have PHP calls these four methods behind the scene whenever we refer to MyClass'
* methods and properties.
*
* The keyword here is: "refer"
*
* For example, to set the property of MyClass, let's first create its instance:
*
* $obj = new MyClass();
*
* // now we can "refer" or set the property using the instance object $obj
* $obj->propA = 100; // property propA = 100
*
* The above reference to the property "propA" will trigger a call to the magic method __set()
* In other words, the code above will trigger a call to the magic method __set($name, $value) with
* $name being the property name propA and $value being the assigned value of 100.
*
* // now to "refer" or get the property
* $var = $obj->propA; // $var = 100
*
* The above reference to the property "propA" will trigger a call to the magic method __get()
* In other words, the code above will trigger a call to the magic method __get($name) with
* $name being the property name propA and holds a value of 100.
*
* If you reference a property in a boolean reference, it will trigger a call to __isset()
*
* In other words, if you reference a property in a test reference to see if the property exists or
* not null, it will trigger a call to __isset()
*
* In another word, this PHP magic method __isset() will be implicitly called when executing
* isset($object->property)
*
* For example: if ($obj->propA) or isset($obj->propA) // it will call __isset()
*
* For __unset(), this PHP magic method __unset() will be implicitly called when executing
* unset($object->property)
*
* For example: unset($obj->propA) // it will call __unset()
*/
class MyClass
{
// declaring properties
private $data = array();
private $username;
private $password;
private $db_name;
private $host;
private $isConnect;
// not used this property
public $declared = 1;
// only used this property when accessed outside the class
private $hidden = 2;
// This is a special magic method that we're using it on a regular basis
// This is in addition to the four magic methods illustrated in the example
public function __construct($user, $pass, $dbName, $url)
{
// initialize the variables username, password, host, db_name, with the
// argument values sent in via the contructor heading: user, pass, dbName, url
// notice that variable $this refers to the current object: $obj = new MyClass()
$this->username = $user;
$this->password = $pass;
$this->db_name = $dbName;
$this->host = $url;
$this->isConnect = $this->Connect();
}
// This is not a magic method, it is just for illustration example only
// In addition to the four magic methods and a special magic method (__construct()),
// you can add your own methods to do other tasks a well,
// and this Connect() is an example of that!
public function Connect()
{
// notice that this function gets called automatically whenever class MyClass
// gets referenced because this function gets included in the constructor above!
// this function returns the PDO connection object
return new PDO("mysql:host=$this->host;dbname=$this->db_name", $this->$username, $this->$password);
}
/**
* // the reference/creation of the MyClass instance below will trigger a call to the constructor
* // this is a PHP's magic method doing its magic behind the scene
*
* $obj = new MyClass('my_username_123', 'my_password_123', 'my_database_name_123', 'my_db_server_123');
*
* // similarly, now when you "refer" or set the property like the following,
* // PHP is doing its magic behind the scene:
*
* $obj->propA = 100; // property propA = 100
*
* The above reference to the property "propA" will trigger a call to the following
* magic method __set($name, $value) with $name being the property name propA and
* $value being the assigned value of 100.
*
* in other words, PHP is doing its magic behind the scene, similarly when PHP is doing its
* magic behind the scene on the constructor __construct(), by calling and executing a magic
* method __set() and assigning a value of 100 to the property name propA.
*
* notice that the magic method __set() is similar to the magic method __construct(), in which,
* they both are empty methods, leaving the methods for you to fill in the blank.
*
* this applies to other magic methods as well, such as: __get(), __isset(), __unset(), etc.
*
* this means that you are freely to put any kind of code inside the magic methods as you see
* fit based on your logic of your applications. however, a typical set() method would contains
* two arguments: set($name, $value) -- hence, the below example being __set($name, $value) with
* $name being the property name propA and $value being the assigned value of 100.
*
* and a typical get() method would contains one argument: get($name) -- hence, the below example
* being __get($name) with $name being the property name propA and holds a value of 100.
*
* notice that property propA have not been declared, but is it being declared and
* used on the spot.
* this is very legal in PHP.
*/
// notice that PHP only calls this magic method and will execute whatever code you place inside it
// this is similar to the constructor __construct() where PHP only calls this magic method
// and will execute whatever code you place inside it
// so it's up to you to put the logic of your application inside this magic method
public function __set($name, $value)
{
echo "Setting '$name' to '$value'\n";
$this->data[$name] = $value;
}
/**
* $obj = new MyClass('my_username_123', 'my_password_123', 'my_database_name_123', 'my_db_server_123');
*
* // now "refer" or get the property
* $var = $obj->propA; // $var = 100
*
* in other words, the above code will cause PHP to do its magic behind the scene
*
* The above reference to the property "propA" will trigger a call to the
* following magic method __get($name) with $name being the property name propA
* in other words, to retrieve the property value contains in property name propA, use
* the code reference above.
*
* notice that property propA have not been declared, but is it being declared and
* used on the spot.
* this is very legal in PHP.
*/
// notice that PHP only calls this magic method and will execute whatever code you place inside it
// this is similar to the constructor __construct() where PHP only calls this magic method
// and will execute whatever code you place inside it
// so it's up to you to put the logic of your application inside this magic method
public function __get($name)
{
echo "Getting '$name'\n";
if (array_key_exists($name, $this->data))
{
return $this->data[$name];
}
$trace = debug_backtrace();
trigger_error(
'Undefined property via __get(): ' . $name .
' in ' . $trace[0]['file'] .
' on line ' . $trace[0]['line'],
E_USER_NOTICE
);
return null;
}
/**
* $obj = new MyClass('my_username_123', 'my_password_123', 'my_database_name_123', 'my_db_server_123');
*
* If you reference a property in a boolean reference, it will trigger a call to __isset()
*
* In other words, if you reference a property in a test reference to see if the property exists or
* not null, it will trigger a call to __isset()
*
* In another word, this PHP magic method __isset() will be implicitly called when executing
* isset($object->property) // with $object being $obj and property being propA
*
* For example: if ($obj->propA) or isset($obj->propA) // it will call the following __isset()
*/
// notice that PHP only calls this magic method and will execute whatever code you place inside it
// this is similar to the constructor __construct() where PHP only calls this magic method
// and will execute whatever code you place inside it
// so it's up to you to put the logic of your application inside this magic method
public function __isset($name)
{
echo "Is '$name' set?\n";
return isset($this->data[$name]);
}
/**
* $obj = new MyClass('my_username_123', 'my_password_123', 'my_database_name_123', 'my_db_server_123');
*
* This PHP magic method __unset() will be implicitly called when executing this:
* unset($object->property)
*
* For example: unset($obj->propA) // it will call the following __unset()
*
* notice that property propA have not been declared, but is it being declared and
* used on the spot.
* this is very legal in PHP.
*/
// notice that PHP only calls this magic method and will execute whatever code you place inside it
// this is similar to the constructor __construct() where PHP only calls this magic method
// and will execute whatever code you place inside it
// so it's up to you to put the logic of your application inside this magic method
public function __unset($name)
{
echo "Unsetting '$name'\n";
__unset($this->data[$name]);
}
// This is not a magic method, it is just for illustration example only
// In addition to the four magic methods, you can add your own methods to
// do other tasks a well, and this getHidden() is an example of that!
public function getHidden()
{
return $this->hidden;
}
}
/* As you can see above, MyClass is a typical class that makes use of the */
/* four magic methods */
/* Note that PHP only calls these four magic methods and passing */
/* the appropriate property name and value (in the case of __set()) */
/* You have to implement the code inside these four magic methods any way */
/* according to your coding logic!!! */
/* Typically, you just set some properties (as shown in __set()) for __set() */
/* and retrieve some properties in the case of __get(), as for __isset(), */
/* check if a property exists in the case for __isset(). */
/* and likewise, perform an unset on the property in the case for __unset() */
/* self-explanatory!!! */
/**
* Usage:
*
* $obj = new MyClass('my_username_123', 'my_password_123', 'my_database_name_123', 'my_db_server_123');
*
* $obj->a = 1; // doing this will trigger a call to __set($name, $value) and will output: Setting 'a' to '1'
* notice the __set($name, $value) with $name being the property a and $value being assign to 1
*
* echo $obj->a . "\n\n"; // will trigger a call to __get($name) and will output: Getting '1'
*
* // notice that property a have not been declared, but is it being declared and
* // use on the spot.
* // this is very legal in PHP.
*
* var_dump(isset($obj->a)); // will trigger a call to __isset()
* unset($obj->a); // will trigger a call to __unset()
* var_dump(isset($obj->a)); // will trigger a call to __isset()
*
* echo $obj->declared . "\n\n";
*
* echo "Let's experiment with the private property named 'hidden':\n";
* echo "Privates are visible inside the class, so __get() not used...\n";
* echo $obj->getHidden() . "\n"; // will not trigger any call to anyone
* echo "Privates not visible outside of class, so __get() is used...\n";
* echo $obj->hidden . "\n";
*
* The above example will output:
*
* Setting 'a' to '1'
* Getting 'a'
* 1
*
* Is 'a' set?
* bool(true)
* Unsetting 'a'
* Is 'a' set?
* bool(false)
*
* 1
*
* Let's experiment with the private property named 'hidden':
* Privates are visible inside the class, so __get() not used...
* 2
* Privates not visible outside of class, so __get() is used...
* Getting 'hidden'
*
*/
?>
There you have it!!!
Parent methods (such as constructors) can be overridden by child classes. To override parent methods, just redefine the parent methods (using the same name) in the child classes. For example, in class Vehicle shown earlier in the previous section, it has a constructor with two argument parameters: __construct($price, $taxRate) and a protected method called calculateTax().
You can define a child class called Toyota that overrides and extends class Vehicle to contain more constructor's argument parameters. Let's create a child class that has a constructor with two additional argument parameters in addition to the two argument parameters that parent class Vehicle already has. For example:
<?php
class Toyota extends Vehicle
{
// declaring class Toyota's properties as private:
private $rebate;
private $carbonTax;
// declaring class Toyota's constructor with two additional parameters
public function __construct($price, $taxRate, $rebate, $carbonTax)
{
/**
* assigning values to class Vehicle's properties
* $this refers to class Vehicle's properties
*/
$this->price = $price;
$this->tax = $taxRate;
/**
* assigning values to class Toyota's properties
* $this refers to class Toyota's properties
*/
$this->rebate = $rebate;
$this->carbonTax = $carbonTax;
}
protected function calculateTax()
{
// getting a tax
$tax = $this->$price x $this->$taxRate + $this->carbonTax - $this->rebate;
return $tax;
}
}
?>
As you can see, the __construct() and calculateTax() methods in the child class (Toyota) override the __construct() and calculateTax() methods in the parent class (Vehicle).
Now to see the effect of the override methods in action in child class Toyota, consider this:
<?php
/**
* now we're creating another class Ford outside of class Vehicle and Toyota.
*/
class Ford
{
// creating an instance of class Toyota which has four parameters:
$obj = new Toyota('25000', '0.07', '5000', '2500');
// call the newly inherited Toyota's method calculateTax()
$obj->calculateTax();
}
?>
Check out the specification of the Public-Key Cryptography Standards (PKCS): The RSA Encryption Algorithm: RFC 8017 Public-Key Cryptography Standards (PKCS)
The RSA is a three-letter acronym derived from the names of its inventors at MIT in the 1970s using their last name's first letter as an acronym: Ron Revest, Adi Shamir, and Leonard Adleman.
The RSA encryption is a military-grade encryption scheme that is being widely used throughout the world, especially in banking applications and other top secret applications.
The RSA uses two keys: one called a public key and another called a private key. We'll discuss about keys later. For now, let's discuss about prime numbers.
The RSA uses prime numbers to create keys to encrypt and decrypt information.
For those of you who are not math inclined, or those who are not really into the historical and theoretical aspects of the RSA encryption, feel free to jump ahead to the implementation section.
For the rest, this section is probably of most significance (and of most importance) to those of you who are working with encryption or security in general. Having a detailed knowledge of how things really work (and why) is essential if you intend to keep your security systems one step ahead of hackers.
Prime numbers have been of interest since the ancient Greek philosophers. However, they were not of interest for theoretical purposes until the latter half of the twentyth century: the 1960s and 1970s when computer technology was beginning to catch fire.
Researchers saw the vulnerability of the information age that computer technology brought and they began to find ways to make the information age secure. A group of researchers at MIT, namely Ron Revest, Adi Shamir, and Leonard Adleman, came on top and their fruit of labor is now being used widely throughout the world.
Let's start with the simplest definiton of a prime number. Prime numbers were discovered by Euclid, sometimes called Euclid of Alexandria.
Euclid was an Ancient Greek philosopher who was born in 300 BC. He was a super, super brilliant mathematician who contributed to the world of mathematics in epic proportion.
In the book VIII of Elements, Euclid defined a prime as a number that has no whole-number divisors other than 1 and the number itself. A few examples of prime numbers would be 2, 3, 5, 11, 13, etc.
As you can see, neither 2, 3, 5, 11, or 13 are divisible by any number other than 1 and itself.
On the other hand, a number that is not a prime is said to be a composite.
Another important definition is called relative prime. But some textbooks call it coprime. I call it relative prime.
A prime number is considered a relative prime to any other number if it does not divide that number. Make note: It does not divide that number! That number is not divisible by a prime!
In other words, a prime number has some relative numbers out there. It has lots of relatives out there. Somewhere in the world of numbers, there are numbers that are relative to this prime number.
Sort of saying a person born without knowing how many relatives he/she has in the world and that person needs to go out and find his/her relatives out there in the world.
The same thing is also true for prime numbers: They need to go out and find their relatives among the numbers in the set.
A prime number cannot divide a number if that number is considered to be a relative prime to a prime number.
This is sort of saying: A person out there whose one or both of his/her parents are not the same as the parent or parents of the person seeking to find relatives CANNOT be a relative to the person seeking to find relatives.
A simplier way of say is that, a person has to share of at least one parent with another person in order to qualify as a relative to that person.
Let's put it this way: If a prime number p is a relative prime to a number n, then: n mod p is not equal to zero. The two numbers are not divisible by one another. We can say that p is a relative prime to a number n or vice versa.
Note: mod is a remainder division function representing modulus operation. So the goal of mod is to return the remainder of a division. For example, 4 mod 2 = 0, 5 mod 2 = 1, 10 mod 5 = 0, and 10 mod 3 = 1 (because 10 divided by 3 resulted in the quotient of 3 with the remainder of 1.)
So if n mod p is equal to zero, it means that n is divisible by p. But n cannot be divisible by p in order to be considered as a relative prime number to p.
Knowing that, we can basically formulate the following three rules or theories or propositions as Euclid called them.
If a prime number p divides a product m * n (with m * n means m multiplies n), then p divides at least one of the two numbers m or n. See proposition 1 illustration below.
By the way, in mathematics, a product is usually written as m * n, as well as m x n, as well as mn, and as well as m.n, too. The latter one with a dot "." notation.
So all four forms: m x n, m * n, mn, and m.n are all valid forms of a mathematical product.
You will see all of the above mathematical forms throughout this tutorial, particularly using parentheses to group multiple entities, for example:
(p - 1)(q - 1) = (p - 1) x (q - 1) = (p - 1) * (q - 1) = (p - 1) . (q - 1)
Every number can be prime or else can be expressed as a product of prime in a way unique, apart from the order in which they are written.
This uniqueness is the key to the RSA cryptography.
A product of prime numbers will result in a prime number as well.
There are indefinitely many prime numbers (in the world of whole numbers.)
Okay, we have three propositions to prove, so let's lay them out one by one and then try to prove them:
Proposition 1:
If a prime number p divides a product mn,
then p divides at least of the two numbers m, n.
Proof:
Let the two numbers m and n multiplied by one another to make another
number o (letter o), and let any prime number p divides o.
Now we must prove that p divides m or n.
Let's assume that p does not divide m, therefore, p and m are relative primes.
Remember the definition of relative prime?
Now let's make another number e such that:
e = mn div p (we could use '/' instead of div as well)
(note: e is the number of units that p divides mn.)
(Make note: div and not mod.)
(div is a division function -- the same as '/'.)
Since p divides mn according to e, then pe = mn.
Therefore, p/m = n/e.
But p is a relative prime to m.
Therefore, they are the least of those that have the same ratio with them.
And the least divides the numbers that have the same ratio (p/n and m/e).
That is, p divides n (and m divides e.)
Similarly, we can also prove that if p does not divide n, then it must divide m.
Next up is Proposition II.
Proposition II is also known as the Fundamental Theorem of Arithmetic.
We'll prove Proposition II in two steps.
First, we can prove that a number can always be factored into primes, and then, secondly, we'll show that this process is unique; that is, there is only one prime factorization for each number.
This uniqueness is the key to the RSA cryptography.
See conclusion for similar statement at the end of Proposition II discussion for this second step.
Those are the two-step processes we are going to have to work through.
Proposition 2:
Every natural (or whole) number is either prime or can be uniquely factored as
a product of primes in a unique way.
Proof
Let's prove this using contradiction.
Let's assume that there are numbers that cannot be written as a product of primes.
Therefore, there must exist the smallest of such numbers; and we'll call it n.
By definition, n must be a natural number greater than 1.
'Nautral' means 'whole' and not fractional number.
So n = ab where a and b are natural numbers such as
a > 1 and b < n.
Therefore, a and b are smaller than n, so a and b can be factored into primes.
For example: n = (a - 1)(b - 1)
By substitution, n can be factored by primes.
This contradicts the assumption that there exist composite numbers that cannot be
factored into primes.
Conclusion: All natural numbers are either primes or can be written as a
product of prime numbers.
Now let's prove that this product is unique, again using contradiction.
This is the second step.
Let's assume that there are numbers that can be factored into primes in at least
two distinct "unique" ways.
Then, there must exist the smallest of such numbers, n,
where n can be represented by:
n = p1p2p3p4p5p6.....pk
OR
n = q1q2q3q4q5q6.....qk
Now let's select one of the members, say, p1.
We can say that p1 divides n, and, therefore,
it divides q1q2q3q4q5q6.....qk as well.
That means that n / p1 = q1q2q3q4q5q6.....qk / p1
But from Proposition I, if p1 divides the product q1q2q3q4q5q6.....qk,
then, p1 must divide at least one of its members, say,
q1 / p1
OR
q2 / p1
OR
q3 / p1
OR
q4 / p1
OR
qk / p1
Since all members on the right side of the equation (p1p2p3p4p5p6.....pk and
q1q2q3q4q5q6.....qk) are primes,
we can say that for a number qj (with 1 ⋜ j ⋝ n),
the following equality holds:
p1 = qj
We can, without loss of generality, assume j = 1
Therefore, p1 = qj
The result of n / p1 is a number smaller than n, and, consequently,
from our initial assumption,
it cannot be factorized in more than one unique ways.
It can only be factorized in one unique way!
Therefore, the consequences p2.....pk and q2.....qk contain the same primes,
possibly different only in their order.
Conclusion: There is only one way to factorize a number into primes.
This uniqueness is the key to the RSA cryptogrophy.
Well, if it wasn't the uniqueness property of the prime,
the RSA cryptography would have not been invented and
the crytography landscape of the world would have been
a lot different than today's environment.
So the uniqueness property of the prime made the RSA cryptography possible.
Proposition 3:
There are indefinitely many prime numbers.
Proof
Let's start with the list: p1, p2, p3, ..... of all known primes.
We must prove that this list continues forever because proposition III states
that there are indefinitely prime numbers out there.
Let's assume that we have listed all primes up to some pm.
Now consider a number p such as:
p = p1p2p3....pm + 1
Note: that is pm + 1 and not pm + 1. Be careful to not confuse the two.
Note that p1p2p3.... means a product of multiple primes.
Likewise, p1p2 means a product of two primes.
If p happens to be a prime,
then p is a prime bigger than pm (because of the product)
and the list can continue (note that p might not be the next prime after pm,
in which case, p cannot be taken to be pm + 1).
If p is not a prime,
then it must be evenly divisible by a prime (Proposition 2).
But none of the primes p1p2p3....pm divides p.
If you carry out such division, you always end up with a remainder of 1.
Therefore, p must be divisible by a prime bigger than all primes up to pm.
Conclusion: We can always find a bigger prime for any given list p1p2p3....pm.
In other words, the list of primes continues forever because there are
indefinitely prime numbers out there.
Taken together, the first two propositions form the building blocks of all natural (or whole) numbers, much like the physicist's atoms.
Knowing the prime number factorization of a number gives complete knowledge about all factors of that number.
Now that we've learned some of the fundamental properties of prime numbers, we need to learn how to find them, and -- most importantly -- how to prove that they are in fact primes.
How do we go about in finding primes?
There are many ways to find primes, and their efficiency usually depends on the size of the primes in which we are interested in, or on the probability of these numbers truly being primes.
One popular method of finding primes is called Sieve of Eratosthenes, which was invented by an ancient Greek philosopher named Eratosthenes in 280 BC.
To verify that n is a prime, follow this two-step process:
Here is a PHP code fragment to list the numbers from 2 to n:
<?php
$n = 2147483647;
$a = array();
$a[0] = 0; // we know that this is not a prime
$a[1] = 0; // we know that this is not a prime
// we start with 2 since 0 and 1 have already been initialzied above
// as you can see, it loops through $n = 2147483647 which
// takes some time to loop through!
// and (FYI) in my computer it overwhelmed the RAM and gives this error message:
// PHP Fatal Error: Allowed memory size of 134217728 bytes exhausted
// (tried to allocate 134217736 bytes)
// what that error message is saying is that the RAM in my computer is too small
// to hold the 134217736 bytes
// anyhow, let's go on in illustrating the code
for ($i = 2; $i < $n + 1; $i++)
{
// initialize all array indexes $a to 1 up to $n
// so $a[2] = 1, $a[3] = 1, $a[4] = 1, $a[5] = 1, ...
$a[$i] = 1;
}
?>
So you start with the smallest number, which is 2, and work your way upward to n.
Then you eliminate all multiples of 2 up to n. For example, what is left is this: 2, 3, 5, 7, 11, 13, ......, n.
Notice that 15 is an odd number but it is not a prime number because in the definition of prime stated earlier, it says a number cannot be divided by another number and 15 can be divided by 3 (which is 5); and therefore, 15 fails the definition of prime.
Likewise, 9 is not a prime number either because 9 can be divided by 3 (which is 3); and therefore, 9 fails the definition of prime as well.
Here is a PHP code fragment to eliminate multiples of 2 up to n:
<?php
$n = 2147483647; // variable $n is an aribitrily number you supply!
$a = array();
$p = 2;
while ($p < $n)
{
// step through multiples of 2
$j = $p * 2; // $j = 4, 6, 8, 10, 12, 14, .....
// variable $n is an aribitrily number you supply!
while ($j <= $n)
{
// eliminate multiples of two up to $n
// and we know that these are not primes
// so $a[4] = 0, $a[6] = 0, $a[8] = 0, $a[10] = 0, ...
$a[$j] = 0;
$j += $p; // $j = $j + $p or $j = 4, 6, 8, 10, 12, 14, .....
} // end while ($j <= $n)
do
{
// $p = 3, 4, 5, 6, 7, 8, 9, 10, 11, .... $n
$p += 1;
}
while ($a[$p] != 1)
} // end while ($p < $n)
?>
So now what is left is this: 2, 3, 5, 7, 11, 13, ......, n.
So what do these numbers in the list that were not eliminated mean?
Well, we'll look at the definition of prime again, and it goes like this: A prime is a number that has no whole-number divisors other than 1 and the number itself.
So the numbers in the list are prime numbers because they are not divisible by any other number other than 1 and themselves. So 2, 3, 5, 7, 11, 13 are prime numbers.
That's all you have to do to find prime numbers.
Although the numbers resulting from this method are sure to be primes, this algorithm is very slow and has exponential complexity, meaning it runs exponentially in the number of digits in the number n. As you can see in the fragment code illustration above, it loops through n = 2147483647 which takes some time to loop through.
Anyhow, let's go ahead and create a function to generate prime numbers using Sieve of Eratosthenes method illustrated above.
Let's put the whole pieces of code illustrated above together to form a complete code.
Here is an implementation of the Sieve of Eratosthenes:
<?php
/**
* finding primes using Sieve of Eratosthenes
*/
public function prime($n)
{
$a = array();
$a[0] = 0; // we know that this is not a prime
$a[1] = 0; // we know that this is not a prime
$p = 2;
// we start with 2 since 0 and 1 have already been initialized above
for ($i = 2; $i < $n + 1; $i++)
{
// initialize all array indexes $a to 1 up to $n, for example:
// $a[2] = 1, $a[3] = 1, $a[4] = 1, $a[5] = 1, ...
$a[$i] = 1;
}
while ($p < $n)
{
$j = $p * 2;
// remember that all array $a was initialized to 1, for example:
// $a[2] = 1, $a[3] = 1, $a[4] = 1, $a[5] = 1, ...
// now the while loop below goes a step further to eliminate any
// array $a (index) that is divisible by 2 (not primes)
while ($j <= $n)
{
// eliminate a multiple of two up to $n
// and we know that these are not primes, for example:
// $a[4] = 0, $a[6] = 0, $a[8] = 0, $a[10] = 0, ...
$a[$j] = 0; // set $a[4] = 0
$j += $p; // now increase $j by 2 (now $j = 6, 8, 10, 12, 14, ....)
} // end while ($j <= $n)
// so after the while loop above, the array $a should now contains
// a number 1 when its index is not divisible by 2, hence it is a prime
// for example, $a[3] = 1, $a[5] = 1, $a[7] = 1, $a[11] = 1, ...
// here, we're looking for primes
// in other words, the do ... while loop below stops/exits once $a[$p] = 1
// meaning, $a[$p] contains a prime number because the first time the loop
// hits the condition $a[$p] = 1 when $p is 3 and then it exits the do .. while loop
// and it goes to the outer while loop: while ($p <= $n) to continue its iteration,
// and this time, $p is 3 and it comes down to execute the do ... while loop again
// now it hits the condition $a[$p] = 1 again when $p is 5 and then it exits
// the do .. while loop, and then it goes to the outer while loop again: while ($p <= $n)
// it repeats this process over and over again until it reaches $n
do
{
// $p = 3, 4, 5, 6, 7, 8, 9, 10, 11, .... $n
$p += 1;
}
while ($a[$p] != 1)
} // end while ($p <= $n)
$k = 0;
$prime = array();
// iterate through n again, but this time we're only
// looking to pick out only primes
for ($i = 2; $i < $n + 1; $i++)
{
// test to see if any of array index $a = 1 up to $n
// if $a = 1 then it is a prime!
// so store it in array $prime for later retrieval
if ($a[$i] != 0)
{
$prime[$k] = $a[$i];
$k++;
}
}
return $prime;
} // end function prime($n)
/**
* prime() above can be called like this:
*
* $n = 50;
*
* $p = prime($n);
*
* foreach ($p as $value)
* {
* echo $value . " ";
* }
*
* output: 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47
*
* or if $n = 100;
*
* output: 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47
* 53 59 61 67 71 73 79 83 89 97
*/
?>
Here is another implementation of the Sieve of Eratosthenes that I want to illustrate. The code illustrated above and the following code (below) will achieve the same result, so that you can see that there are many ways to generate prime numbers. For a better alternative, use PHP's function called gmp_nextprime().
I want to illustrate that the code above is a tidbit slower than the one below; because, as you can see, the code above has four loops that loop from 2 to n, while the one below has only three loops (but four if you count the array_fill() loop, too).
The code above, I could have chosen to use array_fill() instead of the for() loop and both codes would have achieved the same performance. However, I chose to use for() loop just to illustrate that there are many ways to achieve the same result and also to point out that there are performance discrepancies between the two.
In the end, there isn't much meaningful differences in performance between the two -- only the one below is a very tiny, slightly faster only because of the use of the array_fill().
Because of the "computationally intensive" problem, it is generally a normal practice to generate primes randomly rather than using loops (four loops in this case).
In other words, randomly choose a number and then test that number for prime. That way it can be done without loops or fewer loops.
Use Fermat's Little Theorem to test for prime. See a section called Primality Test a little bit later.
If you don't want to use Fermat's Little Theorem to test for prime, it's not the end of the world to use loops (as my illustrations show). As a matter of fact, lots of people have done so for decades without using Fermat's Little Theorem.
However, wise guys tend to choose a random number, say, 3754 (or any number), and test it for prime. That is the quickest way to create prime numbers for your RSA applications.
If you want to use random primes, here is one way to do it.
You could use the Sieve of Eratosthenes code illustrated in this tutorial to create a list of prime numbers and store them in a file or database or some other storage mediums. See my code later about using a json file to store keys.
That way, you don't have to worry about taking too long to create prime numbers on the go, because you already created them and tested them for primes before hand.
Here is one way to do it:
<?php
/**
* First, you have to create primes using Sieve of Eratosthenes method.
* Second, store them in a file, database, or some other mediums.
* Third, when you need random prime numbers, just retrieve them from
* the storage device you created in the second step.
*
* This way, you don't need to create prime numbers on the fly as most
* wise guys often do!
*
* Here is one way to do it:
*/
// retrieve prime numbers from a storage device
// and place them in an array, for example:
$prime = array();
// assuming you're retrieving them from a database
try
{
// assumming $conn is an instance of a PDO
$stmt = $conn->prepare("SELECT prime FROM primetable");
/**
* retrieve prime numbers from the database
* and place them in an array variable: $prime
*/
$prime = $stmt->execute();
}
catch (PDOException $e)
{
echo 'ERROR: Cannot select data from the database: ' . $e->getMessage();
}
// mimicking a random prime number generator
// this example assumes we're working with
// 201 prime numbers: 0 to 200
do
{
$i = rand(0, 200);
$j = rand(0, 200);
$p = prime[$i];
$q = prime[$j];
}
while ($p == $q) // if p == q, keep looking!
// when p and q are distinct, we stop looking and keep them!
// now you can use p and q to calculate your RSA algorithm!
// you might want to put this fragment of code in a function
// and modify it slightly to return p and q
// so that you can call it conveniently!
// or leave it "AS IS" and use the following code to store them!
// remember that p and q are secret keys; and therefore,
// they need to be encrypted and stored in a secure medium
$data = [
"p" => $p,
"q" => $q,
"date" => date("d-m-Y H:i:s") /* displays: 2016-04-26 20:01:04 */
];
try
{
$stmt = $conn->prepare("INSERT INTO keytable (p, q, date)
VALUES (?, ?, ?) ");
/**
* $data contains three items: p, q, date.
* execute the place holder ? ? ?
*/
$stmt->execute($data);
}
catch (PDOException $e)
{
echo 'ERROR: Cannot insert data into the database: ' . $e->getMessage();
}
?>
There are lots of ways to test for prime. Google Miller-Rabin algorithm to test for primes as well.
Better yet, PHP has a function called gmp_prob_prime() which uses the Miller-Rabin algorithm to return primality test result. Function gmp_prob_prime() checks to see if a number is "probably prime."
Example usage: gmp_prob_prime($num).
If this function returns 0, $num is definitely not prime. If it returns 1, then $num is "probably" prime. If it returns 2, then $num is surely prime.
So use this function to your advantage to check if a number is prime or not. Check out the following link:
Side note: Also note that using this form ++$i is 1/3 faster than $i++, which matters for big loops. So I recommend using this form: ++$i (the pre-arithmetic operator) for most of your programming code rather than the post-arithmetic operator: $i++.
<?php
/**
* Sieve of Eratosthenes method of finding primes
*
* php program to print all primes smaller than or equal to n
*
* $n = 2147483647
*/
public function sieveOfEratosthenes($n)
{
// create a boolean array "prime[0..n]"
// and initialize all entries as true.
// a value in prime[i] will finally be
// false if i is not a prime, else true.
$prime = array_fill(0, $n + 1, true);
for ($p = 2; $p * $p <= $n; $p++)
{
// if prime[p] is not changed,
// then it is a prime
if ($prime[$p] == true)
{
// update all multiples of p
for ($i = $p * $p; $i <= $n; $i += $p)
{
// if $prime[$i] is not a prime, return false
$prime[$i] = false;
}
}
}
// print all prime numbers
for ($p = 2; $p <= $n; $p++)
{
if ($prime[$p])
{
echo $p . " ";
}
}
} // end function sieveOfEratosthenes()
/**
* sieveOfEratosthenes() above can be called like this:
*
* $n = 50;
*
* sieveOfEratosthenes($n);
*
* output: 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47
*
* or if $n = 100;
*
* output: 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47
* 53 59 61 67 71 73 79 83 89 97
*/
?>
Create a function that will return an array containing a range of prime numbers. Because of the way in which the algorithm works, the function above isn't possible to generate just a selection of numbers, and as you can see from the output above, the numbers must all be generated and stored in the array variable $prime.
That is not very useful if you just want one prime number to use in your application and not the whole list of primes. The following function aims to achieve that goal.
<?php
/**
* find all the primes up to a given number using
* the Sieve of Eratosthenes algorithm.
*
* @param $start The number to start searching for prime numbers.
* @param $finish The number to stop searching for numbers.
*
* @return array The array of prime numbers.
*/
public function findPrimeRange($start, $finish)
{
// initialize the range of numbers.
$number = 2;
// create an array containing a range of elements from "2" to
// "2147483647":
// $range[2..2147483647]
// Array ( [2] => 2 [3] => 3 [4] => 4 [5] => 5 ...... )
$range = range(2, $finish);
// create an array by using the key elements from first argument as
// key and "value" from the second argument as value
// $prime[2] => 2, $prime[3] => 3, $prime[4] => 4, ....
$prime = array_combine($range, $range);
// loop through the numbers and
// remove the multiples from the primes array.
while ($number * $number < $finish)
{
for ($i = $number; $i <= $finish; $i += $number)
{
if ($i == $number)
{
continue;
}
unset($prime[$i]);
}
$number = next($prime);
}
// slice the array into the given range
foreach ($prime as $p)
{
if ($p < $start)
{
unset($prime[$p]);
}
else
{
break;
}
}
return $prime;
}
/**
*This can be used in the following way.
*
* print_r(findPrimeRange(30, 50));
* Array
* (
* [31] => 31
* [37] => 37
* [41] => 41
* [43] => 43
* [47] => 47
* )
*/
/**
* PHP code to check wether a number is prime or not
* function to check the number is prime or not
*/
public function primeCheck($number)
{
// we know that 0 and 1 are not primes!
if (($number == 0) || ($number == 1))
{
// not a prime
return 0;
}
// we know that 0 and 1 are not primes, so start with 2
for ($i = 2; $i <= sqrt($number); $i++)
{
if ($number % $i == 0)
{
return 0;
}
}
return 1;
}
/**
* Usage:
*
* $number = 31;
* $flag = primeCheck($number);
*
* if ($flag == 1)
* {
* echo "Prime";
* }
* else
* {
* echo "Not Prime"
* }
*/
?>
Check this out to find the next prime number, say, if want to find the next prime number after a certain number, say, 10, gmp_nextprime(10) will return 11. This PHP function is suiteable for looking for a certain prime number after a certain number, say, you want to find a prime number after 2436.
You could use PHP function gmp_nextprime() to your advantage to generate a list of prime numbers. For example:
<?php
/**
* mimicking a random prime number generator
*
* Usage:
* $prime = generatePrime(100);
*
* for() loop will loop through 100 times and generates 100 prime numbers
*/
public function generatePrime($n)
{
for ($i = 0; $i < $n; $i++)
{
// you can make the range as wide or narrow as you want!
// or as large or small as you want!
$j = rand(100, 200000);
// function gmp_nextprime() returns the next prime number after $j
$prime = gmp_nextprime($j);
try
{
// assuming $conn is a PDO object!
$stmt = $conn->prepare("INSERT INTO primetable (prime)
VALUES (?) ");
// execute the place holder ?
$stmt->execute($prime);
}
catch (PDOException $e)
{
echo 'ERROR: Cannot insert data into the database: ' . $e->getMessage();
}
} // end for()
} // end generatePrime()
?>
There you have it! A fast way to generate primes.
Here is more theories about generating primes.
Mathematicians for centuries have been trying to find equations for generating prime numbers, but their success has been slow and valid to only a small range of natural numbers.
Lenard Euler, the Swiss mathematician, came up with the following equation:
f(x) = x2 + x + 41, which is prime for x = 0, 1, 2, ..., 39.
This quadratic equation was the record holder for centuries as a consecutive, distinct quadratic prime-producer for an initial range of input values.
It is not, however, the current record holder. That distinction goes to this function:
f(x) = 36x2 - 810x + 2753, which is prime for x = 0, 1,..., 44.
As you have probably noticed, these functions are also very limiting in their range and are of very little or no practical use.
To be of any real use, we need a method that can produce an infinite number of primes, and of any size we want.
The best way found to deal with this problem, since there are no formulas for finding all prime numbers in sequence, is to instead find numbers that are "very likely" to be primes. Hence, testing for primes or primality.
If we are going to use our primes for industrial uses (e.g., encryption), we often do not need to prove that they are primes.
It may be enough to know that the probability they are composite is less than a given percentage (e.g., 0.000000000000000000000001). In this case, we can use (strong) probable primality tests.
Let's refresh our memory: A number that is not a prime is said to be a composite.
Most of these tests are based on what is known as Fermat's Little Theorem (named after a French mathematician named Pierre de Fermat (1601-1665)).
The Fermat's Little Theorem states:
If p is a prime and if a is any integer, then ap = a (mod p).
In particular, if p does not divides a, then a(p - 1) = 1.
You can't just pick a random number and use it as your RSA encryption key. It won't work. You have to test it for primality using Fermat's Little Theorem. You also can use PHP function gmp_prob_prime() which uses Miller-Rabin algorithm to return primality test result.
Basically, what Fermat's Little Theorem is trying to accomplish is to find the remainder of a number (a raise to the power of (p - 1)) by dividing a(p - 1) by p to equal 1.
That's what this equation a(p - 1) = 1 means.
And that's what the statement: "if p does not divides a, then a(p - 1) = 1" above means.
So p needs to be a prime number in order for it to be a remainder of 1.
Another way of saying is that, the left side divided by p equals to a remainder of 1. So you need to divide the left side by p until the remainder is equal to 1, then stop.
Please check out tutorials on YouTube on Fermat's Little Theorem
Let's see the proof of Fermat's Little Theorem.
Proposition:
If p is a prime and if a is any integer, then ap = a (mod p)
In particular, if p does not divide a, then a(p - 1) = 1.
Proof
Start by listing the first (p - 1) positive multiples of a
For a visual guide, see YouTube tutorials mentioned earlier.
For example:
a, 2a, 3a, .... (p - 1)a
Suppose that ra and sa are the same modulo p, then we have r = s (mod p),
so the (p - 1) multiples of a above are distinct and nonzero; that is,
they must be congruent to 1, 2, 3, ...., (p - 1) in some order.
Multiply all these congruences together and we find:
a.2a.3a .... (p - 1)a = 1.2.3 .... (p - 1) (mod p)
OR better:
a(p - 1) (p - 1)! = (p - 1)! (mod p)
Divide both sides by (p - 1)! to complete the proof.
Don't worry if you don't understand the proof! It's not important!
However, you need to know how to find the remainders of a number.
See YouTube tutorials mentioned earlier.
Conclusion: There is only one way to factorize a number into primes.
As you can see from the above proposition of the Fermat's Little Theorem, there is only one way to factorize a number into primes.
It's important to note that Fermat's Little Theorem is a compositeness test, and not a primality test; that is, it tells you for sure if a number is a composite (not a prime.)
If the test is positive, the number is guaranteed to be a composite, otherwise, it might be a prime.
However, statistically speaking, this method is good enough for many practical applications, including encryption--RSA in particular.
There are 1,091,987,405 primes less than 25,000,000,000; but only 21,853 pseudo-primes base two, which gives us an error probability less than 0.00009% (a very miniscule probability of error -- and we can live with that!).
Note that the term pseudo-prime refers to the result of the primality test to be a positive test (not necessarily that it is a prime. See the primality test above.
We can reduce this margin of error even further by using multiple bases. This is exactly what the Miller-Rabin method does. See next function illustration for the Miller-Rabin Primality Test below.
The Miller-Rabin primality test method gives us a proved probability of error less than 1/s2, where s is the number of bases we tried.
The following code illustration uses a built-in PHP function called gmp_prob_prime() to test the number for primality.
Behind the scene, function gmp_prob_prime() uses Miller-Rabin algorithm to return primality test result.
<?php
$max = 2147483647;
$primeFound = 0;
$probablePrime = 0;
for ($x = 1; $x <= $max; $x++)
{
$primeStatus = gmp_prob_prime($x);
if ($primeStatus == 1)
{
$probablePrime++;
}
else if ($primeStatus == 2)
{
$primeFound++;
}
}
echo "Total primes found between 1 and " . $max;
echo " - certain primes found: " . $primeFound;
echo "probable primes: " . $probablePrime;
?>
Based on that the following results were obtained:
Total primes found between 1 and $max - certain primes found:
1 - 100000 - certain primes found: 9592, probable primes: 0
Total primes found between 1 and $max is:
1 - 1000000 - certain primes found: 78498, probable primes: 0
Total primes found between 1 and $max is:
1 - 10000000 - certain primes found: 78498, probable primes: 586081
Total primes found between 1 and $max is:
1 - 100000000 - certain primes found: 78498, probable primes: 5682957
Total primes found between 1 and $max is:
1 - 1000000000 - certain primes found: 78498, probable primes: 50769036
Total primes found between 1 and $max is:
1 - 2147483647 - certain primes found: 78498, probable primes: 105019067
Don't worry if you don't understand the code above! It's not that important!
It's for illustration purpose only!
Instead, check out PHP documentation on gmp_prob_prime()
?>
Let's focus our attention in finding and factoring primes.
The dual problems of factoring integers and testing primality have surprisingly many applications for a problem long suspected of being only of mathematical interest.
As we'll see below, the security of the RSA public-key cryptograph system is based on the computational intractability of factoring large integers [i.e., (p - 1)(q - 1)].
Before we go on, I want to clarify one term that is being used throughout this tutorial and in other texts describing the RSA cryptography. That term is: factoring or factorize or plainly as factor.
What does it mean?
Well, in mathematics, to factor a number is to derive or break that number into small chunks so that the chunks still retain the original property or meaning.
For example, how many smaller chunks can 6 be broken into?
How many factors can 6 be factored?
Well, let's see the possibilities: 6/6 = 1, 6/1 = 6, 6/2 = 3, 6/3 = 2. Answer: 4 or 4 factors.
Notice that 6/4 = 1.5 and 6/5 = 1.2 are not factorizable.
You'll see later that we multiply two prime numbers (p - 1)(q - 1) to create a public key.
For example: (3 - 1)(5 - 1) = 8
Now 8 is the result of the factorization of (p - 1)(q - 1)
Note: 8 is not the factor of (p - 1)(q - 1). It is the result of factoring (p - 1)(q - 1)
.So that's what the term: factoring or factorize or factorization or plainly as factor means.
Now let's continue on from where we left off:
[A side note: As a more modest application, hash table performance typically improves when the table size is a prime number.
To get this benefit, an initialization function must identity a prime near the desired table size.]
As you imagine, factoring and primality testing are related problems. However, they are quite different algorithmically.
In the sections above, we saw that we can demonstrate that an integer is composite (i.e., not prime) without actually giving the factors.
To convince yourself of the plausibility of this, note that you can demonstrate the compositeness of any nontrivial integer whose last digit is 0, 2, 4, 5, 6, or 8 without doing the actual division.
The simplest solution to factorization is also the simplest one used in primality tests; that is, brute-force trial-division.
However, this is extremely slow for big numbers; and therefore, impractical for any real application.
Another solution, a bit faster than trial-division, is the Square Root Method. See an illustration later.
The Square Root Method is okay for small numbers (15 digits or less), but will become too slow for anything larger than that.
[Note: For heavy-duty industrial commercial encryption purposes, anything less than 150 digits is considered small.]
The Square Root Method as the name implies used square root to implement the function.
The fastest known algorithm used in factorization is the Number Field Sieve. It uses randomness to construct a system of congruences, the solution of which usually gives a factor of the integer.
The method was developed by Pollard and was used to factor the RSA-130 number (such a feat required enormous amounts of computation power.)
As you can see, the strength of encryption algorithms such as RSA relies on the fact that it's really hard to decompose a large number into its factors.
These algorithms use an integer n made of two or more primes, such as: n = p x q or n = p x q x r x s where p, q, r, and s are large prime numbers.
Breaking n into its factors requires an enormous amount of computation that can last for many years (even when using multiple machines).
To demonstrate how secure such algorithms can be, cash prizes were offered to those who manage to factorize these numbers.
This huge disparity between the ease of finding large prime numbers, and the difficulty of factoring large numbers, is fully exploited when devising secure forms of public key cipher systems.
In other words, finding large prime numbers is very easy, but factoring them is very hard.
The basic components of the system are two programs, an encryptor and a decryptor.
Both the sender/encryptor and receiver/decryptor need to have keys.
Typically, the keys will consist of one hundred or more digits -- a very large number. The security of the system depends on keeping some of the keys secret.
This method immediately raises the following question: How can we send the key to the receiver of our message?
If we decide to mail it through a postal mailing system, we need to trust that the mailing system is absolutely 100% secured and tampered proof. Can we trust that? If we send a food recipe to our family and relatives, there is no problem in sending the key through the mailing system.
Or we can always meet up with the person and hand the key to that person days, months, or years in advance and let that person use that key to send us encrypted materials whenever that person needs to do so.
Yeah, we can do that, but it's not very practical for other uses, say, when you want to send a sensitive document to a person far, far away in the other side of the world.
To solve this problem, Whitfield Diffie and Martin Hellman, in 1975, proposed the idea of a public key cryptosystem (PKS).
In a PKS, each potential message receiver A (which would be anyone who intends to use the system) uses a program that will produce not one, but two keys: An encryption key and a decryption key.
The encryption key is made public to all those interested in sending "the receiver" A a message, while the decryption key is kept secret.
Although the basic idea behind such a system is simple, designing it is not.
The one originally proposed by Diffie and Hellman turned out to be not as secure as they had thought, but a method devised a short time later by Rivest, Shamir, and Adleman (the RSA fame) proved to be much more robust and secure, and its byproduct, the RSA system, is now being used widely in international banking, online transactions, military and satellite communications, to name just a few.
The main difficulty for anyone designing such a system is that the encryption process should disguise the message to such an extent that it is impossible to decode it without the decryption key.
But because the essence of the system, and indeed of any cipher system, is that the authorized receiver can decrypt the encoded message, the two keys must be mathematically related.
The receiver's program and decryption key should exactly undo the effect of the sender's program and encryption key, so it should be theoretically possible to obtain the decryption key from the encryption key, provided one knows how the cipher programs work.
The trick is to ensure that, although it is theoretically possible to recover the decryption key from the publicly available encryption key, it is practically impossible.
Let's put it this way: To break the encryption, all you have to do is undoing or unraveling the public key that is publicly made available to anyone, including hackers. In other words, break the public key into its factors of p * q.
In mathematic, undoing the product of p * q means to do a multiplicative inverse of p * q.
So to break the public key, all you have to do is performing a multiplicative inverse of p * q.
This is how hackers break encryption by using computer programs to calculate the multiplicative inverse of the public key.
The public key = p * q
Or it is usually written as n = p * q.
To undo or break the public key, all you have to do is factoring the public key (or n) into its possible factors which is practically impossible if you use large prime numbers.
In the case of one-way ciphers such as RSA, the receiver's secret decryption key consists of two large prime numbers (p and q at least 75 digits each), and the public key consists of their product (a 150-digit number = 75 + 75).
With current technology, it's practically impossible to factor numbers of that size in a reasonable time.
In computer memory, each digit holds 16 bits. So when working with cryptography, you use numbers that are multiples of 16 or divisible by 16. For example, a 1024-bit and 2048-bit keys are divisible by 16.
In general, if you're working with numbers of size N bits, you'll need 2*N bits of storage. Each digit holds 16 bits. So, a 1024-bit key will need 1024 * 2 / 16 = 128 digits of storage.
Let's for the sake of simplicity, we use two primes: 2 and 6; and therefore, the public key becomes 6.
Now all we have to do to unravel the public key is to factor the public key, which is 6, into its original two primes: 2 and 3.
We can do it in our head with these small primes, and even with numbers reasonably large, hackers can still use computer programs to factor these public keys to unravel the public keys.
A computer can quickly compute the greatest common divisor of two numbers using the Euclidean algorithm, so an attacker can run the algorithm on two public keys. If their greatest common divisor is not 1, then the attacker has found a prime number dividing both keys, therefore breaking two keys at the same time.
For example, suppose two public keys were 239149 and 166381. It is difficult to factor either of these two numbers by hand, but the Euclidean algorithm can be done by hand, revealing that the two numbers have a greatest common divisor of 379.
To give you a quick idea of the importance of this algorithm, here are a few of the security protocols that currently implement RSA.
As I mentioned in the previous section, efforts to develop new algorithms to factorize such numbers are usually subjects for doctorate theses and can bring instant fame for those who succeed.
The current record for factorization is around 155 digits.
(Note: New algorithms designed for quantum computers, when and if they ever get to build one, may render this sort of encryption system obsolete, but until then, RSA will continue to be one of the safest encryption systems available.)
To create a good implementation of the RSA algorithm, you need three things:
A pseudo-random number generator to use to generate random primes.
It is generallly a typical practice to create primes using some random methods (i.e., rand()) to generate a random number and then test for prime, rather than just picking some numbers and test for primes. See earlier sections on how to generate primes, especially function findPrimeRange().
Also, be mindful of the "computationally intensive" problem when selecting a range of number to use in findPrimeRange().
Check this out as well to find the next prime number say, if want to find the next prime number after 10, gmp_nextprime(10) will return 11. This PHP function is suiteable for looking for a certain prime number after a certain number, say, you want to find a prime number after 25436.
More on this topic later.
With the facts presented up to this point, we can now start a formal description of the algorithm behind RSA.
The best way to describe it is using the simplest case possible: Where a sender, call it S, wants to send a message to a receiver, call it R.
For the particular case of this example, we will assume that the message is a two-digit integer. For example, 77.
Before it can receive secure messages from S or anyone else interested in sending messages, R will need to generate a public key.
To do this, R must find two large prime numbers, call them p and q, having at least 75 digits, then multiply them to make a number n such as n = p.q.
PHP has a function called bcmul() that multiplies two arbitrary precision numbers p and q. So n = bcmul(p, q).
n will be R's public key (and R should keep p and q a secret).
Somewhere in your coding process, you need to handle the keys gracefully, such as store them in a database or file or some secure medium, while at the same time, making sure that they can be easy access to them so that you can retrieve them quickly and use them.
If you choose to store them in a file, PHP has two functions to make storing/retrieving very easy. These functions are called file_put_contents() and file_get_contents().
// reading/retrieving keys from config file containing keys
$config = json_decode(file_get_contents('http://www.example.com/config/config.json'));
$key_expiration_date = $config['key']['KEY_EXPIRE'];
$login_expiration_date = $config['login']['LOGIN_EXPIRE'];
foreach ($config as $k => $v)
{
if ($k == 'key')
{
// test for certain expiration date and handle it accordingly
// you might find a more elegant way of comparing the two dates than this!
// you get the point!
if ($key_expiration_date > 'today's date')
{
// the expiration date has not been reached ... keys are still good!
// proceed on!
foreach ($v as $key => $value)
{
if ($key == 'P')
{
$p = $value;
}
elseif ($key == 'Q')
{
$q = $value;
}
elseif ($key == 'PUBLIC')
{
$public_key = $value;
}
elseif ($key == 'PRIVATE')
{
$secret_key = $value;
}
} // end inner foreach ($v as $key => $value)
} // end if ($key_expiration_date > 'today's date')
else
{
// keys have expired .... discard old keys and generate new keys!
// and update your json file to reflect your changes!
}
} // end if ($key == 'key')
elseif ($k == 'login')
{
// test for certain login expiration date and handle it accordingly
// you might find a more elegant way of comparing the two dates than this!
// you get the point!
if ($login_expiration_date > 'today's date')
{
// the login expiration date has not been reached ... keys are still good!
// handle login accordingly
}
else
{
// login keys have expired .... discard old keys and generate new keys!
// and update your json file to reflect your changes!
}
} // end elseif ($k == 'login')
} // end outer foreach ($config as $k => $v)
storing keys in the config file
this code below is incomplete due to space constraint.
please check out my other tutorial call "Introduction to Ajax" and navigate
to the very end of that tutorial to find example code similar to the one below.
$config = .......
file_put_contents('http://www.example.com/config/config.json',
json_encode($config, JSON_PRETTY_PRINT));
keys must be encrypted, especially the private key.
there are several pure PHP implementations of the symetry
algorithms on the Web that you can use to encrypt your keys,
such as RC4, AES, DES3, Blowfish, etc.
the process goes like this:
generate two primes and solve for d and then encrypt them and
store them.
when you need to use them, retrieve them and decrypt them and
use them.
there is a pure PHP implementation of the symetry algorithm
RC4 in my other tutorial called "Introduction to RC4."
now a json config.json file looks like this:
{
"key":
{
"P": "1e8f50c3a80b7c0",
"Q": "4a01fb7c0e92b6c",
"D": "0f0c1b3c0e5a218",
"E": "6a9e1f3c0e98b6c",
"PUBLIC": "e201ab3c39c7d4e1d",
"PRIVATE": "0f5b3c390g3d20b3c",
"KEY_EXPIRE": "2592000"
},
"login":
{
"USERNAME": "my_username",
"PASSWORD": "7ac1f1b7c0e92b6f",
"LOGIN_EXPIRE": "2592000"
}
}
note: do not embedd any comment in your json file!
basically, once you've retrieve this json file,
you can convert it into an array using json_decode() so that
you can iterate through your array as you normally would!
one last note:
it is a good idea to tie your keys to an expiration date,
so that you can discard them and issue new keys.
this practice adds extra security to your security system.
you can timestamp your key file and read the timestamp
of that file and compare it against the current timestamp.
for example, a value for a 24-hour timestamp is: 3600 * 24 * 30
or 2,592,000 miliseconds.
PHP's current timestamp function is: time()
$time is 24 hours old, it's 24 hours ago, it's yesterday!
$time = time() - (3600 * 24 * 30);
if your file time was created two days, filemtime() should
be less than $time. confusing?
check out PHP doc for filemtime()
filemtime() returns Unix timestamp in milliseconds: '20452718039105'
for example:
$filemtime = filemtime('http://www.example.com/config/config.json')
if ($filemtime < $time)
{
// expired
// do something!
}
how you implement such system is up to you!
the example shown here is not the only way to do it!
Besides the generation of the public key, R should agree with S on a method to encode the actual message text.
Now let's break the process of encrypting and decrypting the message into steps:
R needs to select two primes (see previous sections on finding primes, particularly function findPrimeRange()). Here, we'll use p = 17 and q = 31, for example.
Note that p and q must be kept secret.
But keep in mind that in real applications, this number must be at least 75 digits, depending on how secure you want your message to be.
As a rule of thumb, use a somewhat small number for your "not so important" message so that you don't consume too much processing power.
You increase the number accordingly as your message gets more sensitive.
That's why maintaining a storage device, i.e., file or database, for storing different levels of security is very crucial.
R now generates n by multiplying p and q. Such as n = 17 x 31; that is n = 527.
527 will be R's public key.
R now must calculate phi, which denoted by a Greek letter ϕ.
ϕ = (p - 1)(q - 1).
phi = (p - 1)(q - 1), which is 16 x 30 or 480.
R now chooses another number called it e (stands for encryption) which must meet these two conditions:
1. e must be between 1 and phi or 480.
2. e also must be a relative prime to phi or 480.
Remember the definition of relative prime?
To refresh your memory: A prime number is considered a relative prime to any other number if it (prime) does not divide that number. Another way of saying is that, choose a number e that is not divisible by the prime.
So e cannot divide 480. Or 480 is not divisible by e.
By the definition of relative prime, we know that the following numbers cannot divide 480: 7, 11, 13, 14, etc.
And 7, 11, 13, 14,.... must be between 1 and 480, so they all satisfy both conditions for step 4.
Notice that 14 is an even number and yet it does not divide 480. So it satisfies the definition.
Also notice that e doesn't need to be an odd number (as the even number 14 shows).
Now in real life (application) the hard part is finding e, especially if you're not math-inclined and especially when numbers must be very large as is the case when you program real RSA cryptography applications.
Basically, finding e comes down to finding a number e such as the Greatest Common Divisor (or GCD) between e and 480 is 1.
In other words, it's this equation: GCD(e, 480) = 1.
But not this equation: GCD(e, 480) = 0.
See an example down below on how to use this GCD(e, 480) = 1.
In practice, e is often chosen to be 216 + 1 = 655372, though it can be as small as 3 in some cases. In other words, do not choose e higher than 655372.
If your phi is larger than 655372, choose e between 3 and 655372 but no higher than 655372.
e will be the other half of the public key (and n is the other half).
Basically, the Greatest Common Divisor of two integers A and B is the largest integer that divides both A and B.
In other words, the Greatest Common Divisor of two integers e and 480 is the largest integer that divides both e and 480.
The Euclidean Algorithm is a technique for quickly finding the GCD of two integers.
PHP has a function to solve GCD. It's PHP's GMP extension. Check this out: Find the Greatest Common Divisor of two integers
To use the PHP's GMP extension, see an example illustrated below.
Once you solve this equation: GCD(e, 480) = 1 using the Euclidean Algorithm to quickly find the GCD of two integers, or using the example illustrated below, then that is your number e for your step 4.
Here is an example on how to use the GCD(e, 480) = 1.
This example checks to verify that gcd(e, phi) is 1:
To verify that the greatest common divisor (GCD) of e and phi is 1 in PHP,
you need a function to calculate the GCD and then check if the result is equal to 1.
PHP's GMP extension is recommended for this, especially since RSA encryption often involves very large numbers.
Using the GMP Extension (Recommended for large numbers)
The gmp_gcd() function efficiently calculates the GCD of two numbers, including large integers.
public function verify_gcd_is_one_gmp($e, $phi)
{
// Convert inputs to GMP numbers
$gmp_e = gmp_init($e);
$gmp_phi = gmp_init($phi);
// Calculate the GCD
$gcd = gmp_gcd($gmp_e, $gmp_phi);
// Convert the GCD back to an integer or string for comparison
$gcd_value = gmp_intval($gcd);
// Check if the GCD is 1
if ($gcd_value === 1)
{
return true; // gcd(e, phi) is 1, they are coprime
}
else
{
return false; // gcd(e, phi) is not 1
}
}
// Example usage:
$e_val = 7;
$phi_val = 60; // Example: (p - 1) * (q - 1) for p = 5, q = 13 is 4 * 12 = 48, for p = 3, q = 5 is 2 * 4 = 8
// For p = 7, q = 13, phi = 6 * 12 = 72. Let's use 7 and 72. GCD(7, 72) is 1.
$e_val = 7;
$phi_val = 72;
// Here is the code that calls our function verify_gcd_is_one_gmp() above
if (verify_gcd_is_one_gmp($e_val, $phi_val))
{
echo "GCD($e_val, $phi_val) is 1. The numbers are coprime.\n";
}
else
{
echo "GCD($e_val, $phi_val) is not 1. The numbers are not coprime.\n";
}
// Another example where GCD is not 1:
$e_val_2 = 3;
$phi_val_2 = 396; // GCD(3, 396) = 3
if (verify_gcd_is_one_gmp($e_val_2, $phi_val_2))
{
echo "GCD($e_val_2, $phi_val_2) is 1. The numbers are coprime.\n";
}
else
{
echo "GCD($e_val_2, $phi_val_2) is not 1. The numbers are not coprime.\n";
}
Pure PHP Function (for smaller integers)
If you are certain your numbers will fit within standard integer limits and you cannot use the GMP extension,
you can implement the Euclidean algorithm in pure PHP:
public function gcd_pure_php($a, $b)
{
while ($b != 0)
{
$t = $a % $b;
$a = $b;
$b = $t;
}
return abs($a);
}
public function verify_gcd_is_one_pure_php($e, $phi)
{
$gcd = gcd_pure_php($e, $phi);
return $gcd === 1;
}
// Example usage:
$e_val = 7;
$phi_val = 72;
if (verify_gcd_is_one_pure_php($e_val, $phi_val))
{
echo "GCD($e_val, $phi_val) is 1. The numbers are coprime.\n";
}
else
{
echo "GCD($e_val, $phi_val) is not 1. The numbers are not coprime.\n";
}
Please check out tutorials for the subject of Greatest Common Divisor on the Web, particularly on YouTube. It will make you a better RSA cryptosystem programmer.
Or you can just modify the above functions [verify_gcd_is_one_gmp() and verify_gcd_is_one_pure_php() to suit your objective and go from there. I recommend using the verify_gcd_is_one_gmp() as it is more robust and can handle large numbers.
Here are two of them:
The Extended Euclidean Algorithm to find the GCD of two integers The Extended Euclidean Algorithm to find the Modular Inverse of a number: How To Find The Inverse of a Number ( mod n ) - Inverses of Modular ArithmeticIn mathematic, an inverse of a number, n, is written as n-1 or 1/n.
Knowing that, we can use the Euclidean Algorithm to quickly solve the inverse of a number, say, 27, and then take a modulo of another number, say, 392.
Likewise, we can solve the inverse of a number, say 11, and then take a modulo of another number, say, 480.
Later, I will show you how to calculate Euclidean Algorithm to find GCD(A, B) = 1.
For now let's forge on the rest of the description of the RSA algorithm.
If you look at the very beginning of this step 4, it says R needs to choose a number e. You can choose any number between 1 and 480 that does not divide 480 and it will work out just fine.
This is very easy using function findPrimeRange(1, 480) to list prime numbers between 1 and 480.
How you pick out a particular prime number from function findPrimeRange() is up to you.
However, it is very easy to do, for example, assuming prime holds the array of prime range generated by function findPrimeRange() [i.e., prime = findPrimeRange(1, 480)], you can easily pick out the array index: prime[3], prime[38], or prime[115], etc.
Let's do that now from the list: 7, 11, 13, 14, etc.
[Note: findPrimeRange() starts with prime[0] = 2, prime[1] = 3, prime[2] = 5, prime[3] = 7, prime[4] = 11]
Let's pick e = 11 for this example (or more specifically prime[4] = 11]).
The number e (11 in this case) is also part of the public key; and therefore, R will have to make it public together with n.
Make note: e and n are public keys. R can give both e and n to anyone that wants to send R messages.
So step 4 looks like this: GCD(11, 480) = 1
With the knowledge of n and e, the sender S can now prepare to send the message to R.
Let's call this message M.
It is necessary to convert the message M into a number because the RSA uses numbers to calculate the algorithm. One common conversion process uses the ASCII alphabet.
For this example, the message in our case is a single two-digit number. For example: M = 77. The ASCII code for M is 77.
It could be a file containing pages of texts, i.e.:
THE RED COATS ARE COMING! THE RED COATS ARE COMING! THE RED COATS ARE COMING! ....
T = 84, H = 72, E = 69, a space = 32, R = 82, E = 69, D = 68, C = 67, O = 79, A = 65, T = 84, S = 83, a space = 32, A = 65, R = 82, E = 69, a space = 32, C = 67, O = 79, M = 77, I = 73, N = 78, G = 71, ! = 33.
For example, the message (M) THE RED COATS ARE COMING! would be encoded as 847269328269686779658483326582693267797773787133.
As you can see, that is an anormous large number. It is important that M < n, as otherwise the message will be lost when taken modulo n. In other words, the number 847269328269686779658483326582693267797773787133 raise to any power will be too computationally intensive and the computer will go haywire on you.
So if n is smaller than the message, as is often the case, it will be sent in pieces. In our example, n = 527, but our M is 77.
So it seems that we don't need to send the message character by character.
Now with n = 527 and M is 77, what else can we send? Not many characters. Try 'Me' = 7769. That is over 527.
So no need to worry about M < n in this case. We'll send M as a single character.
Make note: If n is smaller than M, then S will have to send the message character by character (as our example M = 77 shows).
If you have a long string like THE RED COATS ARE COMING!, send it one character at a time using our example (M = 77) as a guide.
Use loop(s) to loop through the encryption process, encrypting one character at a time.
Likewise, on the decryption side, use loop(s) to loop through the decryption process, decrypting one character at a time.
Later, as a bonus material, I probably will show you a secret of sending long strings like THE RED COATS ARE COMING! broken into smaller pieces (if I have time) by using loops to convert ASCII characters to its ordinal number and back to its original ASCII character.
Other alternatives are to use one of the symetry encryptions like AES (Advanced Encryption Standard), DES (Data Encryption Standard), IDEA (International Data Encryption Algorithm), Blowfish (Drop-in replacement for DES or IDEA), RC4 (Rivest Cipher 4), RC5 (Rivest Cipher 5), RC6 (Rivest Cipher 6), etc.
I recommend using RC4 because it is fast and simple to use and millions of people, industries, and organizations have been using it for decades to send secure large documents. See my tutorial on RC4.
As for AES, DES, and IDEA are too overkilled for the majority of us who don't need military-grade encryption. Blowfish is also a little overkilled for the majority of our encryption tasks.
As for RC5 and RC6 are proprietary algorithms and you need to obtain permission from RSA Security to use them. That left us the RC4 as the best alternative to use.
So if you need military-grade encryption, use RSA encryption algorithm described in this tutorial, and for non-military-grade encryption, use RC4.
S now encrypts the message by appplying a sequence of mathematical operations over M that will result in the encrypted message C:
C = M e mod n, which for this example becomes:
C = 77 11 mod 527 or C = 8.
n and e are public keys.
Besides the public keys, the equation is the only information an attacker will be able to steal. Of course, you keep M as a secret, too.
To solve this equation, please check out tutorials on YouTube on Fermat's Little Theorem as well as on the subject of Greatest Common Divisor (on YouTube) listed below.
The following lists PHP's precision arithmetic functions that are suiteable for programming RSA encryption.
PHP has two functions for dealing with exponential and modulus -- the same sort of equation listed above. Please check these out:
bcpowmod() gmp_powm() to raise a number to a power with moduloIf your numbers are small enough not to cause memory overflow then using the two functions as well as other functions mentioned in this tutorial to calculate your RSA equations is fine. You have to decide of what level of security you're comfortable with your data and implement your RSA applications accordingly.
While you're at it, please check the following out as well. You probably will need to use a lot of these functions in your RSA algorithm code.
By the way, the function names listed below contain a "bc..." prefix, which stands for "basic calculator," because this precision arithmetic library extends from a GNU implementation utility interface created by Philip Nelson.
A simplier way of saying is that, the people at PHP created this precision arithmetic library by extending it from a GNU implementation utility interface created by Philip Nelson, and therefore, inheriting all of the functionalities from the parent interface.
See my other tutorial called "abstract verses interface" for more about how interfaces work.
Please note that Philip Nelson called it incorrectly as "basic calculator," but the people at PHP called it correctly as "binary calculator."
bcmod() mod() exp() pow() bcadd() bcsub() bcmul() bcdiv() bccomp() rand() array-rand() random_int()For more PHP mathematical functions check these out:
GMP Functions Mathematical Extensions Mathematical Extensions: Math_BigInteger PHP Secure Communications LibraryAs you can see from the functions above, all of these functions can handle large precision numbers, and you might be tempted to just calculate your RSA in raw fashion -- that is, calculate this equation
C = 77 11 mod 527 and this equation M = 8 131 mod 527 without breaking them down using
Euclidean Algorithm.
That will cause RAM memory problems.
If you watch the tutorials on YouTube mentioned above, particularly Fermat's Little Theorem, you will hear them say that a calculator is overwhelmed by the sheer large numbers that the equation C = 77 11 mod 527 or M = 8 131 mod 527 generates. It overflows the available memory.
So you can't use the functions listed above to solve all these equations in raw form because the equations contain exponential number that is typically too large for the RAM memory to handle and it is computationally too intensive. You have to break them down into small pieces using Euclidean Algorithm or some other means.
You can use the functions listed above for a reasonably medium size exponential numbers but not for larger exponential numbers, especially exponential larger than two digits such as 723 131 and 8 631. This one is probably okay: 723 11.
Remember that an RSA key that is more than 2500 bits is very very computationally expensive even just to generate it.
It's not the functions that cause the problems -- it's the computer's memory called RAM memory that is causing the problems.
Remember that the RAM memory is like a blackboard you find in schools for teachers to write on.
You know that a blackboard does not have a lot of spaces for a teacher to write on, so a teacher has to erase the chalk so that he/she can write new materials on. The RAM memory is the same thing. It has a limited space for programs to run on.
A calculator also uses RAM memory as its chip.
So take this warming seriously and break the equations into small pieces. Use the Euclidean Algorithm and Fermat's Little Theorem techniques to solve your equations.
Having said that, with a stern warning, you can still use the precision arithmetic functions listed earlier to calculate your RSA in raw fashion if your security level doesn't need to use large exponential numbers as long as you practice a sound encryption process.
In other words, you can still use a reasonably small number (or exponential number) according to your security level and still be secured as long as you practice a sound encryption process by encoding your encryption using bases, i.e., base16, base32, base64, base92, etc.
As a matter of fact, thousands and thousands of people, industries, organizations have been using these functions in raw fashion without having to break their equations into small pieces because they practice sound encryption process, such as encoding their encryption using bases, i.e., base16, base32, base64, base92, etc.
Please see my other tutorial called Introduction to Base64 Encryption.
You can also use sample codes from 'users contributed' section of the base_convert()
Encoding your RSA encryption adds extra security and makes it very very hard to break your RSA algorithm.
See bonus materials later where you break your strings into small pieces, and at the same time, encrypt those pieces twice: one with your RSA algorithm and after that, with the base encoding process to make it very very hard to break.
Not only that, you can also wrap your encryption using RC4 algorithm as well (on top of everything else) to make it even more hard to break -- making it a triple encoded firewalls. That is a very sound encryption process that you should always practice.
Now R, after receiving the encrypted message C, must decrypt it using the secret pair of prime numbers (p and q) used to create the public key.
R must first find another number call it d (stands for decryption) such that:
e.d mod (p - 1)(q - 1) = 1.
To compute the value for d, use the Extended Euclidean Algorithm to calculate d = e-1 mod phi, also can be written as d = 1/e mod phi.
This is known as modular inversion. Note that mod is not integer division. It's a remainder division.
The modular inverse d is defined as the integer value such that ed = 1 mod phi.
It only exists if e and phi have no common factors.
In other words, d only exists if e and phi have no common factors.
Basically (in our case), find d = (1/e) mod 480.
In our case, we can substitute the above equation (e.d mod (p - 1)(q - 1) = 1) with actual values:
11.d mod 480 = 1.
In other words, compute d = (1/e) mod 480.
Or it can be written in a formal mathematic notation like this: d = (1/e) mod 480 = 1.
But we're going to use this notation to compute d = (1/e) mod 480.
Now compute the right hand side for d.
We know the value of e = 11, so compute d = (1/11) mod 480 using the following tutorial on YouTube:
How To Find The Inverse of a Number ( mod n ) - Inverses of Modular Arithmetic.An inverse of a number 11 is written as 11-1 or 1/11
Or we can just pick d that satisfy this condition: d = (1/11) mod 480 = 1.
As you maybe well aware that there are several choices for d that will work out just fine for our equation.
Again, we can quickly find some suitable candidates for d, for example: d = 131 satisfies the condition.
The problem of finding d is equivalent to finding the modular inverse of a number.
Here is an example in finding d.
The equation e * d * (mod(p - 1)(q - 1)) = 1 [also can be written as e.d mod (p - 1)(q - 1) = 1] is used in the RSA algorithm to find the private key exponent d, which is the modular multiplicative inverse of the public key exponent e modulo ϕ(n) = (p - 1)(q - 1).
The most common and efficient method of finding the modular multiplicative inverse is the Extended Euclidean Algorithm.
PHP has a native function, gmp_invert(), which can be used to find this value directly, as long as e and (p - 1)(q - 1) are coprime (their greatest common divisor is 1).
Here is an example PHP function to find the value of d:
public function findModularInverse($e, $p, $q)
{
// Calculate the modulus, also known as Euler's totient function, phi(n)
$phi = gmp_init(($p - 1) * ($q - 1));
// The gmp_invert() function calculates the modular multiplicative inverse
// The result is 'd'
$d = gmp_invert($e, $phi);
// gmp_invert returns a GMP resource or false if the inverse does not exist
if ($d === false)
{
return false;
}
return gmp_strval($d);
}
Example usage:
$p = 11;
$q = 13;
$e = 7;
$d = findModularInverse($e, $p, $q);
if ($d !== false)
{
echo "The value of d is: " . $d;
echo "\nVerification: " . ($e * $d) . " mod (" . (($p - 1) * ($q - 1)) . ") = " . (($e * $d) % (($p - 1) * ($q - 1)));
}
else
{
echo "The modular inverse does not exist.";
}
?>
Again, please check out tutorials for the subject of Modular Inverse of a number on the Web, particularly on YouTube. It will make you a better RSA cryptosystem programmer.
PHP has a function to solve Modular Inverse of a number. Check this out:
Find the modular inverse of a GMP number (GNU Multiple Precision : For large numbers)For example:
$inverse = gmp_invert("11", "480");
echo gmp_strval($inverse) . "\n";
While you're at it, check this out as well:
Find the modular inverse of a number: See 'Users Contributed' at the bottom of that page.Here is a function to compute the modular inverse of an integer using Extended Euclidean Algorithm that mimicks the PHP's gmp_invert() above:
<?php
// function to compute the modular inverse of an integer
public function Euclidean($a, $b)
{
// initializing players
$x = '1';
$y = '0';
$mod = $b;
do
{
// first, find the remainder of dividing a by b
$remainder = bcmod($a, $mod);
// next, find the quotient of dividing a by b
$q = bcdiv($a, $mod);
// now re-arranging the players
$a = $mod;
$mod = $remainder;
// now finishing up the calculation
$remainder = bcsub($x, bcmul($y, $q));
// now re-arranging the players again to be run through the loop again
$x = $y;
$y = $remainder;
}
while (bccomp($mod, '0')); // while (b == '0')
// test to see if b == '0'
// if it is, we're finished calculating, add b to x
// and then return x
if (bccomp($mod, '0') < 0)
{
$x = bcmadd($x, $b);
}
return $x;
} // end function Euclidean()
Usage:
$num = "64941057316178801556773346239351236811";
$mod = "2447995268898324993537772139997802321";
// verifying that ($num * $m) * Euclidean($num) is equal to $m
$m = "123456789";
$i = Euclidean($num, $mod);
// then test it out to see if the function works by
// verifying that ($num * $m) * Euclidean($num) is equal to $m
// you need to echo out this equation:
// echo bcmod(bcmul(bcmod(bcmul($num, $m), $mod), $i), $mod);
// if (bcmod(bcmul(bcmod(bcmul($num, $m), $mod), $i), $mod) == $m)
// if the left side equals to the right side, it works!
?>
Finally, to decode the message, R applies a sequence of mathematical operations on C as follows:
M = C d mod n, which for this example becomes:
M = 8 131 mod 527 or M = 77.
In other words, R translates M back into its original alphabet letter, retrieving the original message: M = 77.
Here is a video on YouTube on the subject of Modular Inverse of a number that explains it very well: How To Find The Inverse of a Number ( mod n ) - Using Fermat's Little Theorem.
As you can see, as long as R can keep the original two primes used to generate the public key a secret, he can be sure that messages addressed to him cannot be decoded and read or tampered with by anyone else.
So R needs to keep the original two primes a secret, but can give n and e to anyone that wants to send messages to him.
R can even give n and e to hackers (just in case if hackers want to hack messages other people sent to R).
That's it!
Just follow these eight steps just outlined and you're on your way to programming applications very secure.
This concludes the formal RSA Algorithm tutorial. What you'd learned thus far will enable you the knowledge necessary to program very secure and powerful security applications. The sky is the limit! And don't forget to thank me later!
For the rest of the materials, they are just extra (bonus) materials to help you understand RSA algorithm further.
Recap:
Let's refresh our memory again about our eight steps.
Create two prime numbers called them p and q.
p and q must be kept a secret.
Find n = p * q.
Create a function called phi = (p - 1) * (q - 1).
Find e, which stands for the encryption public key.
e must satisty two conditions:
1. 1 < e < phi
2. e must be a relative prime to phi.
The two conditions above can be easily handled using this function findPrimeRange().
For example, e = findPrimeRange(1, phi)
Prepare the message using either a character by character encoding or by other means.
One popular and very efficient method is to use ordinal character conversion and manipulation to make the numbers condensed which is suitable for use in RSA calculations.
See a detail description later described in a section called "RSA Calculations in PHP Without Using OPENSSL," which uses two functions, function stringToBigInt() and function bigIntToString(), to convert ordinal character numbers to be used in RSA calculations.
Find d, which stands for the decryption private key.
d must be kept a secret.
The basic formula used to encrypt a message M is this:
C = M e mod n
where M is the plain text message and C is the resulting encrypted message.
And e will be dependent on the two initial two primes (p and q) used to generate n. Notice that e stands for encryption.
e and n are public keys and can be given to anyone that wants to send messages. You can even give them to hackers as well.
The basic formula used to decrypt a message C is this:
M = C d mod n
where d (stands for decryption) will be dependent on the two initial two primes (p and q) used to generate the public key n.
Again, d is the private key and must be kept a secret.
Those are the eight steps in implementing RSA encryption application.
That is it!
As you can see from the two formulas for both encryption and decryption, the syntax for both is the same; and that is, a number M or C raise to the power (e or d) and then mod n. The only difference between the two formulas is the base number (M or C) and the raise power number (e or d).
This means that you can create only one function to calculate both encryption and decryption by passing to this function the appropriate values and the function should return the correct algorithm accordingly.
For example:
/**
* assuming $num is the number to be raised to the power $power
* and then modulo $mod, we can write the function for both
* encryption and decryption like this:
*/
public function rsa($num, $power, $mod)
{
// return the result of the calculation: M e mod n or C d mod n
// just remember to be mindful of the concept called
// "computationally intensive!"
}
/**
* Usage:
*
* $encrypt = rsa($encryption_number, $power_e, $mod_n);
*
* $decrypt = rsa($encrypt, $power_d, $mod_n);
*
* as you can see, you still call the same function, but with different values!
*/
By the way, the eight steps outlined above and the description described in this tutorial is not pertain to just PHP - it applies to other languages as well. You can implement RSA alogrithm described in this tutorial in other languages as well, such as Javascript, just to name one.
Later, I will provide Javascript precision arithmetic functions that mimick PHP's precision arithmeth functions listed earlier.
You can use most of them to do your own implementation of RSA alogrithm described in this tutorial.
Check out these videos on YouTube as well:
The RSA Encryption Algorithm (1 of 2: Computing an Example) The RSA Encryption Algorithm (2 of 2: Generating the Keys) The RSA Encryption Algorithm: Public Key Crypto with RSA)Check out the Public-Key Cryptography Standards (PKCS):
The RSA Encryption Algorithm: Public-Key Cryptography Standards (PKCS)Now that you know an extensive detail about RSA Algorithm, you can use that knowledge to program very powerful and secure applications on your own.
However, as is always the case, there are lots of third-party tools out there that you can use to make your life easier. For example, to generate the public and private keys, you can use a tool called OpenSSL.
Please Google it.
See my other tutorial called Introduction to OpenSSL.
OpenSSL is a very popular tool that is widely being used all over the world. OpenSSL uses the RSA Algorithm that just outlined in this tutorial to generate both public and private keys and as well as certificates.
There are countless tools out there that use RSA Algorithm to make your life easier so that you don't have to do the hard math yourself. Check this out:
PHP Secure Communications LibraryFor your information: Nowaday, the RSA Algorithm is not the only algorithm available out there. There are plenty of algorithms out there available for your use. To list just a few, here they are: AES, DES, Blowfish, RC6 (an extension of Rc4), Rijndael, Serpent, MARS.
Please Google them.
Advanced Encryption StandardAdvanced Encryption Standard (AES) is a symmetric block cipher chosen by the U.S. government to protect classified information. AES is implemented in software and hardware throughout the world to encrypt sensitive data. It is essential for government computer security, cybersecurity and electronic data protection.
Symmetric, also known as secret key, ciphers use the same key for encrypting and decrypting, so the sender and the receiver must both know -- and use -- the same secret key.
The National Institute of Standards and Technology (NIST) started development of AES in 1997 when it announced the need for an alternative to the Data Encryption Standard (DES), which was starting to become vulnerable to brute-force attacks.
Blowfish is an encryption technique designed by Bruce Schneier in 1993 as an alternative to DES Encryption Technique. It is significantly faster than DES and provides a good encryption rate with no effective cryptanalysis technique found to date. It is one of the first, secure block cyphers not subject to any patents and hence freely available for anyone to use.
RC6 is a derivative of RC5 (and RC5 is a derivative of RC4) and is a block cipher designed for RSA Security. RC6 uses four working block size registers in its algorithmic computations, whereas RC5 uses only two. Thus, RC6 is faster. RC6 was designed as part of the Advanced Encryption Standard (AES) competition, where it was a finalist. It is a propriety algorithm patented by RSA Security.
So to use the RC5 or RC6, you have to obtain a permission for their uses. However, the RC4 is not patented and is freely available for anyone to use.
Rijndael (pronounced rain-dahl) is the algorithm that has been selected by the U.S. National Institute of Standards.
Rijndael is a symmetric key encryption algorithm that's constructed as a block cipher. It supports key sizes of 128, 192 and 256 bits, with data handling taking place in 128-bit blocks. In addition, the block sizes can mirror those of their respective keys.
The Rijndael Block Cipher - NIST Computer SecurityAs stated earlier, to create a good implementation of the RSA algorithm, you need three things, which were listed earlier.
One of the three things is that, you need to do a precision arithmetic (actually multiple precision arithmetics).
Feel free to skip this RSA Algorithm Arithmetic section and jump to the RSA Algorithm Implementation section ahead to see the actual implementation of the RSA algorithm using what w've learned thus far, plus using the upcoming RSA algorithm arithmetic as well.
Okay, let's touch bases on some of the arithmetics involved in the RSA algorithm using precision arithmetics.
As you may already know, the PHP functions listed above is enough for calculating precision RSA Algorithm Arithmetic. But sometimes, you need Javascript precision arithmetics as well. The following are Javascript functions that mimic the behaviors of PHP precision arithmetic functions listed above.
/**
* initilize cryptography functions of the specified bits
*
* function initcrypt(bit)
* {
* if (bit != 0)
* {
* setTimeout(('sendinit(' + bit + ')'), 200);
* }
* }
*
* returns a to the power of b mod c
*
* Ah.... this function needs a refinement!
*
* Usage:
*
* function sendinit(bit)
* {
* rc4key = rand(0, 9) + rand(0, 9) + rand(0, 9) + rand(0, 9) +
* rand(0, 9) + rand(0, 9) + rand(0, 9) + rand(0, 9);
*
* while (rc4key.length + 8 <= RSAmodulok.length - 3)
* {
* rc4key += (rand(0, 9) + rand(0, 9) + rand(0, 9) + rand(0, 9) +
* rand(0, 9) + rand(0, 9) + rand(0, 9) + rand(0, 9));
* }
*
* ibPowmodInPart(rc4key, RSApublick, RSAmodulok, '1', 0);
* }
*
*/
function ibPowmodInPart(a, b, c, r, i)
{
// RSA encryption is broken up into parts
// because it is computationally expensive
r = ibmod(ibmul(r, a), c);
i++;
if ( i < parseInt(b))
{
var h = 'ibPowmodInPart("' + a + '", "' + b + '", "' +
c + '", "' + r + '", "' + i + '")';
setTimeout(h, 500);
}
else
{
return r; // returns the results to caller
}
}
// Integer Binary Math library
// returns 0 on equel, 1 on a > b, -1 on a < b
// in other words, it returns true if a > b
function ibgreater(a, b)
{
a = a + '';
b = b + '';
if (a.length > b.length)
{
return 1;
}
if (a.length < b.length)
{
return -1;
}
var i = 0;
while (a.charAt(i) == b.charAt(i) && i < a.length)
{
i++;
}
if (i == a.length)
{
return 0;
}
if (a.charAt( i) > b.charAt(i))
{
return 1;
}
else
{
return -1;
}
}
// returns a + b
function ibadd( a, b)
{
a = a + '';
b = b + '';
var l = a.length;
while (b.length < l)
{
b = '0' + b;
}
if (b.length > l)
{
l = b.length;
}
while (a.length < l)
{
a = '0' + a;
}
l--;
var c = 0;
var r = '';
for (var i = l; i > = 0; i--)
{
c = c + parseInt(a.charAt(i)) + parseInt(b.charAt(i));
if (c > 9)
{
c = c - 10;
r = '' + c + r;
c = 1;
}
else
{
r = '' + c + r;
c = 0;
}
}
if (c == 1)
{
r = '' + c + r;
}
while (r.charAt(0) == '0' && r.length > 1)
{
r = r.substring(1);
}
return r;
}
function ibsub(a, b)
{
// returns a - b or NV9999. . . if b > a
a = a + '';
b = b + '';
var r = '';
var l = a.length;
while (b.length < l)
{
b = '0' + b;
}
if (b.length > l)
{
l = b.length;
}
while (a.length < l)
{
a = '0' + a;
}
l--;
var c = 0;
var r = '';
for (var i = l; i >= 0; i--)
{
c = parseInt(a.charAt(i)) - parseInt(b.charAt(i)) - c;
if (c < 0)
{
c = c + 10;
r = c + r;
c = 1;
}
else
{
r = c + r;
c = 0;
}
}
while (r.charAt(0) == '0' && r.length > 1)
{
r = r.substring(1);
}
if (c == 1)
{
r = 'NV' + r;
}
return r;
}
// returns a * b
function ibmul(a, b)
{
a = a + '';
b = b + '';
var v = [a];
var vr = [1];
var i = 0;
while (ibgreater(b, vr[i]) != -1)
{
v[i + 1] = ibadd( v[i], v[i]);
vr[i + 1]= ibadd( vr[i], vr[i]);
i++;
}
var r = '0';
var d = b;
for (var i = v.length - 1; i >= 0; i--)
{
if (ibsgreater(d, vr[i]) != -1)
{
r = ibadd(r, v[i]);
d = ibsub(d, vr[i]);
}
}
return r;
}
// returns a / b
function ibdiv(a, b)
{
a = a + '';
b = b + '';
if (ibgreater(b, '0') == 0)
{
return 'NV';
}
if (ibgreater(a, b) == -1)
{
return '0';
}
if ( ibgreater(a, ibadd(b, b)) == -1)
{
return '1';
}
var r = 0;
var d = a;
var v = [b];
var vr = [1];
var i = 0;
var t = '';
while (ibgreater(d, v[i]) == 1)
{
v[i + 1] = ibadd(v[i], v[i]);
vr[i + 1] = ibadd(vr[i], vr[i]);
i++;
}
for (var i = v.length - 1; i >= 0; i--)
{
if (ibgreater(d, v[i]) != -1)
{
d = ibsub(d, v[i]);
r = ibadd(r, vr[i]);
}
}
return r;
}
// returns a mod b
function ibmod(a, b)
{
//return ibsub(a, ibmul(b, ibdiv(a, b)));
a = a + '';
b = b + '';
if (ibgreater(b, '0') == 0)
{
return 'NV';
}
if (ibgreater(a, b) == -1)
{
return a;
}
var r = 0;
var d = a;
var v = [b];
var vr = [1];
var i = 0;
var t = '';
while (ibgreater(d, v[i]) == 1)
{
v[i + 1] = ibadd(v[i], v[i]);
vr[i + 1] = ibadd(vr[i], vr[i]);
i++;
}
for ( var i = v.length - 1; i >= 0; i--)
{
if (ibgreater(d, v[i]) != -1)
{
d = ibsub(d, v[i]);
r = ibadd(r, vr[i]);
}
}
return d;
}
// raise a to power b
function ibpow(a, b)
{
a = a + '';
b = b + '';
var v = [a];
var vr = [1];
var i = 0;
while (ibgreater(b, vr[i]) != -1)
{
v[i + 1] = ibmul(v[i], v[i]);
vr[i + 1] = ibadd(vr[i], vr[i]);
i++;
}
var r = '1';
var d = b;
for (var i = v.length - 1; i >= 0; i--)
{
if (ibgreater(d, vr[i]) != -1)
{
r = ibbmul(r, v[i]);
d = ibsub(d, vr[i]);
}
}
return r;
}
// small power mod
function ibpowmod(a, b, c)
{
a = a + '';
b = b + '';
c = c + '';
var r = '1';
for (var i = 0; i < parseInt(b); i++)
{
r = ibmod(ibmul(r, a), c);
}
return r;
}
Here are two Javascript functions to find the GCD
of two integers a and b:
This one uses while loop to achieve the result:
function gcd(a, b)
{
var r;
while ((a % b) > 0)
{
r = a % b;
a = b;
b = r;
}
return b;
}
This one uses recursive calls to achieve the result:
function gcd(a, b)
{
if (b == 0)
{
return a;
}
else
{
return gcd(b, (a % b));
}
}
Next up is the Greatest Common Divisor.
Okay, let's go over the Greatest Common Divisor involved in the RSA algorithm.
Warning This tutorial is very confusing and complex. So please use tutorials on YouTube instead.
The Euclidean Algorithm for finding GCD(A, B) is as follows:
The above illustration can be written in code like this:
<?php
// if everything divides 0
if ($a == 0 || $b == 0)
{
return 0;
}
?>
Example:
Find the GCD of 270 and 192
Or as an equation: GCD(270, 192) = 1
Another way of illustration for the above case can be written in code like this:
<?php
function Euclidean($a, $b)
{
// you know from basic math: any number divides 0 is 0
if ($a == 0 || $b == 0)
{
return 0;
}
}
?>
Again, we can write it as an equation: GCD(192, 78) = 1
And we can continue on until GCD(192, 78) = 0, as you can see from the following pattern.
A = 192, B = 78
A = 78, B = 36
A = 36, B = 6
A = 6, B = 0
So we have shown that:
GCD(270, 192) = GCD(192, 78) = GCD(78, 36) = GCD(36, 6) = GCD(6, 0) = 6
So we found the final answer to be: 6.
Or more specifically:
GCD(270, 192) = 6
That's it!
If we examine the Euclidean Algorithm we can see that it makes use of the following properties:
The first two properties let us find the GCD if either number is 0.
That's why at the begining of this Euclidean Algorithm, we point out these two cases to solve:
The above illustration can be written in code like this:
<?php
// if everything divides 0
if ($a == 0 || $b == 0)
{
return 0;
}
?>
The third property lets us take a larger,
more difficult to solve problem,
and reduce it to a smaller,
easier to solve problem.
This third property is the lengthy process we just did.
And we got the answer to be 6.
The Euclidean Algorithm makes use ofWe can understand why these properties work by proving them.
We can prove that GCD(A, 0) = A is as follows:
The proof for GCD(0, B) = B is similar.
(Same proof, but we replace A with B).
To prove that GCD(A, B) = GCD(B, R) we first need to
show that GCD(A, B) = GCD(B, A - B).
Suppose we have three integers A, B and C such that A - B = C.
Proof that the GCD(A, B) evenly divides C
The GCD(A, B), by definition, evenly divides A.
As a result, A must be some multiple of GCD(A, B).
i.e. X.GCD(A, B) = A where X is some integer.
The GCD(A, B), by definition, evenly divides B.
As a result, B must be some multiple of GCD(A, B).
i.e. Y.GCD(A, B) = B where Y is some integer.
A - B = C gives us:
So we can see that GCD(A, B) evenly divides C.
An illustration of this proof is shown in
the left portion of the figure below:
Proof that the GCD(B, C) evenly divides A
The GCD(B, C), by definition, evenly divides B.
As a result, B must be some multiple of GCD(B, C).
i.e. M.GCD(B, C) = B where M is some integer.
The GCD(B, C), by definition, evenly divides C.
As a result, C must be some multiple of GCD(B, C).
i.e. N.GCD(B, C) = C where N is some integer.
A - B = C gives us:
So we can see that GCD(B, C) evenly divides A.
An illustration of this proof is shown in the figure below
Proof that GCD(A, B) = GCD(A, A - B)
GCD(A, B) must be less than or equal to, GCD(B, C), because
GCD(B, C) is the "greatest" common divisor of B and C.
GCD(B, C) must be less than or equal to, GCD(A, B), because
GCD(A, B) is the "greatest" common divisor of A and B.
Given that GCD(A, B) = GCD(B, C) and
GCD(B, C) = GCD(A, B) we can conclude that:
GCD(A, B) = GCD(B, C)
Which is equivalent to:
GCD(A, B) = GCD(B, A - B)
An illustration of this proof is shown in the
right portion of the figure below.
Proof that GCD(A, B) = GCD(B, R)
We proved that GCD(A, B) = GCD(B, A - B)
The order of the terms does not matter so we can
say GCD(A, B) = GCD(A - B, B)
We can repeatedly apply GCD(A, B) = GCD(A - B, B) to obtain:
GCD(A, B) = GCD(A - B, B) = GCD(A - 2B, B) = GCD(A - 3B, B) = ... = GCD(A - Q.B, B)
But A = B.Q + R so A - Q.B = R
Thus GCD(A, B) = GCD(R, B)
The order of terms does not matter, thus:
GCD(A, B) = GCD(B, R)
Question: Find gcd(421, 111).
Answer:
We use the Euclidean algorithm as follows:
this is basically using the form: A = B.Q + R,
with Q is the quotient from dividing A by B and R is the remainder.
421 = 111 x 3 + 88 larger number on left (i.e. 421). if B is larger, then put B on left
111 = 88 x 1 + 23 shift left by moving B to the left and shift R in place of B
88 = 23 x 3 + 19 note how 19 moves down "diagonally" all the way to the left side
23 = 19 x 1 + 4
19 = 4 x 4 + 3
4 = 3 x 1 + 1 last non-zero remainder is 1 <--- this is our answer in this case
3 = 1 x 3 + 0
The last non-zero remainder is 1 and therefore gcd(421, 111) = 1.
Notice that it could be any number other than 1. It just happens that this equation turns out to be 1.
The thing to remember is that, once your equation resulted in a remainder of zero, then stop and use the last non-zero remainder as your final answer.
Now that we know how GCD works, let's put it into code.
This code still haven't solve the "computationally intensive" problem when you have large exponential numbers.
In that case, you still have to break it down into small pieces.
Hopefully, this code example below will give you enough idea to proceed to program RSA encryption that is very secure using large exponential numbers.
<?php
/**
* PHP program to find modular inverse of a
* under modulo m using Fermat's little theorem.
* This program works only if m is prime.
*
* See function modInverse() below that makes use of this gcd() function
*
* Usage:
*
* $a = 3; $m = 11;
* modInverse($a, $m);
*
* To compute x raised to the
* power of y under modulo m
*
* See function modInverse() below that makes use of this gcd() function
*
* Recursive function to
* return gcd of a and b
*/
public function gcd($a, $b)
{
/**
* anything that divide 0 is equal to 0
* make note: not divide by zero, which is undefined
*
* 0/30 = 0, 0/-1 = 0, 0/5 = 0
*
* so the equation GCD(0, B) = 0
* so the equation GCD(A, 0) = 0
*/
if ($a == 0 || $b == 0)
{
return 0;
}
// if both are the same, return either one of them
if ($a == $b)
{
return $a;
}
// if a is greater
if ($a > $b)
{
/**
* continue to recursively call itself if $a > $b
*
* remember the equation GCD(A, B) = 1 ?
*
* for example: GCD(270, 192) = 1
*/
return gcd($a - $b, $b);
}
/**
* or else continue to recursively call itself if $a < $b
*/
return gcd($a, $b - $a);
}
Here is a much faster function to do the same thing as above:
public function gcd($a, $b)
{
return $b ? gcd($b, $a % $b) : $a;
}
// Function to find modular
// inverse of a under modulo m
// Assumption: m is prime
public function modInverse($a, $m)
{
if (gcd($a, $m) != 1)
{
// echo "Inverse doesn't exist";
return null;
}
else
{
// If a and m are relatively prime,
// then modulo inverse is
// a(m - 2) mode m
// echo "Modular multiplicative inverse is ",
// power($a, $m - 2, $m);
return power($a, $m - 2, $m);
}
}
// To compute xy under modulo m
public function power($x, $y, $m)
{
if ($y == 0)
{
return 1;
}
$p = power($x, $y / 2, $m) % $m;
$p = ($p * $p) % $m;
return ($y % 2 == 0) ? $p : ($x * $p) % $m;
}
// here is a function (largePrecisionPowMod()) to mimick PHP's bcpowmod()
// for any exponent greater than a few tens of thousands,
// you can use this function!
// as you can see, this function uses PHP's bcpowmod() if it is available
// if you don't want to use PHP's bcpowmod() just comment out the "if" statement block!
public function largePrecisionPowMod($base, $power, $modulus)
{
// check if PHP's bcpowmod() is available
// if it is available, use it!
if (function_exists("bcpowmod"))
{
return bcpowmod($base, $power, $modulus);
}
// start with 1
$result = "1";
// loop until the exponent is reduced to zero
while (TRUE)
{
if (bcmod($power, 2) == "1")
{
$result = bcmod(bcmul($result, $base), $modulus);
}
// when the exponent is reduced to zero, we exit the loop
// and return $result
if (($power = bcdiv($power, 2)) == "0")
{
break;
}
$base = bcmod(bcmul($base, $base), $modulus);
} // end while
return ($result);
}
?>
Earlier, I mentioned about converting text to its ordinal number so that it can be used in the RSA algorithm.
So here, I want to share a secret with you all that no one will never bother to tell you about. But I will!
Here is one way to do it.
Remember that the encryption/decryption formulas given earlier work with exponential numbers (or powers), and when working with RSA applications often require you to work with large numbers to make RSA application more secure. The following is an attempt to reduce the numbers to a more manageable so that we can use them in the encryption/decryption formulas given earlier.
The most frequently used method of code is the ordinal number of the ASSCII code and it can be very large given how long your text message you want to encrypt.
If you have a long string like THE RED COATS ARE COMING! (or longer), you can format the long string by breaking it down into small pieces.
Remember M = 77 example shown earlier?
Well, you can think of each small piece as M or 77.
But each small piece will contain a much larger number than the two-digit M has.
Refer to the code below where we have a variable called $result which basically holds a sum of the products of all of the characters: THE RED COATS ARE COMING! by multiplying each of its ordinal numbers (847269328269686779658483326582693267797773787133) together and add them all together to make it much and much smaller than the actual ordinal numbers listed here.
So this is the secret: create a 'sum of the products of all of the ordinal character numbers to make it much and much smaller to be used in the RSA encryption/decryption formulas given earlier.' See the code below.
Now the code below assumes the long string of THE RED COATS ARE COMING! as one piece.
If you have longer string, you can break it down using PHP's function str_split() to split your long string into pieces, and then use loops to loop through the code shown below. You can think of variable $string (below) as one of the pieces broken down by str_split().
When breaking your long string into pieces using str_split(), be mindful of the concept computationally intensive, because your 'sum of the products of all of the ordinal character numbers' in each piece can be large as well.
Not only that, you will have to raise your 'sum of the products of all of the ordinal character numbers' in each piece to the power of your number e or d.
Let's see the code that converts regular piece of string into the sum of all the products of their ordinal numbers. In other words, let's make each piece of the long string to look like M or 77.
// turn regular text into a number that can be manipulated by the RSA algorithm
// in other words, let's turn regular text's ordinal numbers into a smaller number,
// particularly the exponential numbers, that can be used and manipulated by the RSA algorithm
// variable $string is just one piece for this example
// in a real application, variable $string could contain a very long text or pages of document
// but you'll have to break it (variable $string) into pieces and loop it through the pieces
// one way to do it is to create a function and put this snippet of code in it and pass in
// the variable $string as one piece and return it back to your application and then
// make another call to your function again and repeat this same process until you're done!
// self-explanatory!
$string = 'THE RED COATS ARE COMING!';
$result = '0';
$n = strlen($string); // n is 25
while ($n > 0)
{
// reduce $n by 1 to 24, so $string[24] = !
// remember that $string[0] = T, $string[1] = H, $string[2] = E,
// $string[3] = a space
--$n;
// $result is analogous to the message 'M' described in this tutorial!
// $result basically holds a sum of the products of all of these characters:
// THE RED COATS ARE COMING! by multiplying each of its ordinal numbers
// by 256 and add them all together as well
// notice that the ASCII values only go up to 256 in total
// as you can see, we work from the end of the string ($string[24] = !) and then
// work our way toward the beginning of the string: $string[0] = T
$result = bcadd(bcmul($result, '256'), ord($string[$n]));// ASCII values only go up to 256
} // end while
// the above while loop converts THE RED COATS ARE COMING! to
// 847269328269686779658483326582693267797773787133 and then
// sum all of the products of all their ordinal numbers to make the number
// smaller that can be used and manipulated by the RSA algorithm
// you might want to encode $result with base: 16, 32, 64, etc.
echo $result;
As far as using these ordinal numbers in the RSA algorithm is concern, you might want to wrap this while loop (above) in your RSA algorithm process described in this tutorial. Or put it in a function and call that function repeatedly. See similar functions that I've created in a section below called "RSA Calculations in PHP Without Using OPENSSL" and they are called stringToBigInt() and bigIntToString().
The above code is similar to the two functions that I've created below and they achieve the same result. So it is just a matter of preference or choice which version of the code you choose to use in your application as both version work just fine.
For extra security, you might want to encode each piece of your RSA algorithm above/below using bases of your choice, for example: base 16, base32, base64, base92, etc, to make your RSA algorithm even more secure and robust.
Please see my other tutorial called Introduction to Base64 Encryption.
You can also use sample codes from 'users contributed' section of the base_convert()
Likewise, you can convert the ordinal number to its original ASCII character after you decrypted your message using RSA algorithm described in this tutorial.
Here is one way to do it:
// turn the numeric representation of text back to its original ASCII text after
// it has been manipulated by the RSA algorithm
// variable $num is just one piece for this example
// in a real application, you might need to create a function and put this snippet of code
// in it and pass in the variable $num as an argument containing just one piece of the string
// and return it back to your application and then make another call to your function again
// and repeat this same process until you're done!
// in other words, break your string into small pieces and pass them one by one as $num
// actually, $num is the result calculated in the previous example containing in the variable $result
// so use the result in variable $result from the previous example as $num
// self-explanatory!
$num = 847269328269686779658483326582693267797773787133;
// as noted above, $num does not contain ordinal numbers
// it contains the sum of products of ordinal numbers. so make not of that!
// again, $num contains the value found in the variable $result from
// the previous example!
// so $num = $result
$result = ''; // initialize $result to null
do
{
// $result will hold the original message 'THE RED COATS ARE COMING!'
$result .= chr(bcmod($num, '256')); // ASCII values only go up to 256
$num = bcdiv($num, '256');
}
while (bccomp($num, '0'));
// the above while loop converts 'the sum of products of ordinal numbers'
// back to:
// THE RED COATS ARE COMING!
// don't forget to decode $result if you encoded it!
echo $result;
Here is another example that is similar to the two code illustrations above and they achieve the same result. So it is just a matter of preference or choice which version of the code you choose to use in your application as both version work just fine.
To convert a string of text into a large ordinal number (integer representation) for use in custom RSA calculations in PHP without openssl, and then convert it back, you must use PHP's GMP (GNU Multiple Precision) or BCMath arbitrary precision arithmetic extensions to handle the large integers involved in RSA.
Standard PHP integers are not large enough for secure RSA (which typically requires 2048-bit keys or larger).
The process involves treating the message as a byte array (octet string), then converting that byte array into a single, large big-endian integer, and vice versa.
Ensure your PHP environment has the GMP or BCMath extension enabled. GMP is generally preferred for performance.
The string is converted into a byte stream (using a consistent encoding like UTF-8), which is then interpreted as a single large integer in big-endian format.
Here is the code:
public function stringToBigInt($string)
{
// Ensure consistent encoding, e.g., UTF-8
$bytes = utf8_encode($string);
$bigInt = '0'; // Initialize as string for BCMath or GMP
// Use GMP for handling large numbers
for ($i = 0; $i < strlen($bytes); $i++)
{
// Shift left by 8 bits (multiply by 256) and add the current byte's ordinal value
$bigInt = gmp_strval(gmp_add(gmp_mul($bigInt, 256), ord($bytes[$i])));
}
return $bigInt; // The large number as a string
}
Here is how to use the function above.
$originalString = "Hello, this is a somewhat large string of text for RSA calculation."; $messageAsInt = stringToBigInt($originalString); echo "Original String: " . $originalString . "\n"; echo "Message as Large Integer: " . $messageAsInt . "\n\n";
Note: For very large strings, you must chunk the data, as RSA can only encrypt messages smaller than its key size (modulus N).
The reverse process involves repeatedly taking the modulus of the large number by 256 to get the last byte's value and then dividing the number by 256 until it reaches zero.
public function bigIntToString($bigInt)
{
$bytes = [];
$number = gmp_init($bigInt); // Initialize GMP number
while (gmp_cmp($number, 0) > 0)
{
// Get the remainder when divided by 256 (the last byte's value)
$remainder = gmp_mod($number, 256);
$bytes[] = gmp_intval($remainder);
// Integer division by 256 (shift right by 8 bits)
$number = gmp_div_q($number, 256);
}
// Bytes are collected in reverse order, so reverse the array and convert to string
$bytes = array_reverse($bytes);
$string = '';
foreach ($bytes as $byte)
{
$string .= chr($byte);
}
// Decode from UTF-8 to the original format
return utf8_decode($string);
}
Here is how to use the function above:
$decodedString = bigIntToString($messageAsInt); echo "Decoded String: " . $decodedString . "\n";
Manually implementing RSA is strongly discouraged for production use as it is extremely difficult to get the padding schemes (like PKCS#1 v1.5 or OAEP) correct, which are crucial for security.
Text-book RSA (unpadded) is insecure. For any real-world application, use PHP's built-in openssl functions or a well-vetted library like phpseclib.
There you have it!
My secret to encrypt long strings (or pages of document!)
You might have to tweek the code above a little bit to suit your objective, like breaking down your long string using str_split() and loop through each piece using the above two code examples as guide.
Hopefully, the two code illustrations above will help you implement your own robust and secure RSA applications containing large documents.
The sky is the limit!
And don't forget to thank me later!
Now that we thoroughly covered all of the theoretical bases, it's time to create our own implementation of the RSA algorithm. Don't forget to make use of PHP precision arithmetic functions (bc...) listed earlier.
There are seven functions that we need to write. For example:
First, you could use PHP function gmp_nextprime() to generate a list of prime numbers. For example:
<?php
/**
* mimicking a random prime number generator
*
* Usage:
* $prime = generatePrime(100);
*
* for() loop will loop through 100 times and generates 100 prime numbers
*/
public function generatePrime($n)
{
for ($i = 0; $i < $n; $i++)
{
// you can make the range as wide or narrow as you want!
// or as large or small as you want!
$j = rand(100, 200000);
// function gmp_nextprime() returns the next prime number after $j
$prime = gmp_nextprime($j);
try
{
// assuming $conn is a PDO object!
$stmt = $conn->prepare("INSERT INTO primetable (prime)
VALUES (?) ");
// execute the place holder ?
$stmt->execute($prime);
}
catch (PDOException $e)
{
echo 'ERROR: Cannot insert data into the database: ' . $e->getMessage();
}
} // end for()
} // end generatePrime()
?>
Next, retrieve the prior generated prime numbers from the database.
<?php
/**
* when you need random prime numbers, just retrieve them from
* the storage device you created before hand
*/
public function getKey()
{
// retrieve prime numbers from a storage device
// and place them in an array, for example:
$prime = array();
try
{
// assumming $conn is an instance of a PDO
$stmt = $conn->prepare("SELECT prime FROM primetable");
/**
* retrieve prime numbers from the database
* and place them in an array variable: $prime
*/
$prime = $stmt->execute();
}
catch (PDOException $e)
{
echo 'ERROR: Cannot select data from the database: ' . $e->getMessage();
}
// mimicking a random prime number generator
// this example assumes we're working with
// 201 prime numbers: 0 to 200
do
{
$i = rand(0, 200);
$j = rand(0, 200);
$p = prime[$i];
$q = prime[$j];
}
while ($p == $q) // if p == q, keep looking!
// when p and q are distinct, we stop looking and keep them!
// remember that p and q are secret keys; and therefore,
// they need to be encrypted and stored in a secure medium
// use rc4 to encrypt these keys and store them in a secure medium
$data = [
"p" => $p,
"q" => $q,
"date" => date("d-m-Y H:i:s") /* displays: 2016-04-26 20:01:04 */
];
try
{
$stmt = $conn->prepare("INSERT INTO keytable (p, q, date)
VALUES (?, ?, ?) ");
/**
* $data contains three items: p, q, date.
* execute the place holder ? ? ?
*/
$stmt->execute($data);
}
catch (PDOException $e)
{
echo 'ERROR: Cannot insert data into the database: ' . $e->getMessage();
}
return $data;
} // end getKey()
?>
Next, generate the two prime numbers (p, q) needed to be used in the RSA algorithm. I prefer this (below) function as appose to the one above, because all you need is just two primes and not a whole database of prime numbers.
For some scenarios, the above function will serve you well -- say, you have some records that you want to encrypt and decrypt it later. Have your keys stored in a database is a "MUST" -- otherwise, your data are useless if you don't store your keys for a later retrieval and use them later. So storing your prime numbers and keys are not useless (nor bad ideas) -- in fact, they are part of the sound encryption practice.
<?php
/**
* mimicking a random prime number generator
*
* Usage:
* $prime = generateTwoPrime(20000);
*
* make $this->prime an array of 2 primes under 20,000
* meaning that the 2 prime numbers can range anywhere from 2 to 20,000 in strength
* remember that the larger the number the stronger the encryption algorithm
* so in theory both p and q could be as small as 2 and as large as 20,000
*/
public function generateTwoPrime($n)
{
//
$prime = [];
// mimicking a random prime number generator
// this example assumes we're working with
// number range: 0 to 20,000 ($n) but we only want two prime numbers out of 20,000
// that is a very large range to choose from
$i = 0;
$j = 0;
do
{
$i = rand(0, $n);
$j = rand(0, $n);
// function gmp_nextprime() returns the next prime number after $i or $j
$p = gmp_nextprime($i);
$q = gmp_nextprime($j);
}
// if p == q and ($p < 100 && $q < 100), keep looking because we don't want the two primes that are the same and less than 100!
while (($p == $q) && ($p < 100 || $q < 100));
// if p and q are distinct, and also they are bigger than 100, we keep them as our two primes
$prime = [$p, $q];
return $prime;
} // end generateTwoPrime()
?>
Next, get the public key e.
<?php
/**
* Using step 4 instruction to find a random relative prime number e: a public key e
*
* Usage:
*
* $prime = generateTwoPrime(200000);
*
* // find e by passing prime numbers p and q
* $relativePrime = getE($prime[0], $prime[1]);
*
* make $relativePrime relative prime number bigger than 1 and less than phi (or 480 in the example shown in the tutorial step 4)
*
* This is basically performing step 4 by choosing a number e, for example:
* now I have to pick a number e (for step 4) that meets this conditions: 1 < e < $phi
*/
public function getE($p, $q)
{
// Find phi
$phi = bcmul(bcsub($p, 1), bcsub($q, 1));
// mimicking a random relative prime number generator that meets this conditions: 1 < e < $phi
$i = 0;
do
{
// since random() includes both starting and ending numbers, we need to start from 2 and end with $phi - 1
// in other words, generate a random relative prime number that meets this conditions: 1 < e < $phi
// this is performing step 4 by choosing a number e
$i = rand(2, $phi - 1);
// function gmp_nextprime() returns the next prime number after $i
$e = gmp_nextprime($i);
$mod = bcmod($phi, $e); // find the remainder by dividing $phi by $e
}
// if $phi mod $e == 0, it is not a relative prime, and therefore, just keep looking for the relative prime number until we find one
while ($mod == 0);
// when $phi mod $e != 0, then it is a relative prime
$relativePrime = $e;
return $relativePrime;
} // end getE()
?>
There are so many ways to achieve the same result as the one shown above, and here is another way to do it to get the same result and get the public key e.
<?php
/**
* Using step 4 instruction to find a random relative prime number e: a public key e
*
* Usage:
*
* $prime = generateTwoPrime(200000);
*
* // find e by passing prime numbers p and q
* $relativePrime = getE($prime[0], $prime[1]);
*
* make $relativePrime relative prime number bigger than 1 and less than phi (or 480 in the example shown in the tutorial step 4)
*
* This is basically performing step 4 by choosing a number e, for example:
* now I have to pick a number e (for step 4) that meets this conditions: 1 < e < $phi
*/
public function getE($p, $q)
{
// Find phi
$phi = bcmul(bcsub($p, 1), bcsub($q, 1));
// mimicking a random relative prime number generator that meets this conditions: 1 < e < $phi
$random = 0;
do
{
// this is basically performing step 4 by choosing a number e that meets this conditions: 1 < e < $phi
// since random() includes both starting and ending numbers, we need to start from 2 and end with $phi - 1
// in other words, generate a random relative prime number e that meets this conditions: 1 < e < $phi
$random = rand(2, $phi - 1);
// this time we'll use PHP's function gmp_prob_prime()
// if this function returns 0, $random is definitely not prime
// if it returns 1, then $random is "probably" prime
// if it returns 2, then $random is surely prime
$num = gmp_prop_prime($random);
if ($num == 2)
{
// $random is definitely a prime
$e = $random;
}
else
{
continue;
}
$mod = bcmod($phi, $e); // find the remainder by dividing $phi by $e
}
// if $phi mod $e == 0, it is not a relative prime, and therefore, just keep looking for the relative prime number until we find one
while ($mod == 0);
// when $phi mod $e != 0, then it is a relative prime
$relativePrime = $e;
return $relativePrime;
} // end getE()
?>
Next, calculate the Extended Euclidian Algorithm to find the private key d.
<?php
/**
* generating the private key d
*
* Usage:
*
* Find d using the Extended Euclidian Algorithm: $d = euclid($e, $phi);
*
* See function getD() below
*/
public function euclid($num, $mod)
{
// The Extended Euclidian Algorithm
$x = '1';
$y = '0';
$num1 = $mod;
do
{
$temp = bcmod($num, $num1);
$q = bcdiv($num, $num1);
$num = $num1;
$num1 = $temp;
$temp = bcsub($x, bcmul($y, $q));
$x = $y;
$y = $temp;
}
while (bccomp($num1, '0'));
if (bccomp($x, '0') < 0)
{
$x = bcadd($x, $mod);
}
return $x;
} // end euclid()
?>
Next, get the private key d.
<?php
/**
* generating the private key d
*
* Usage:
*
* $d = getD($e, $phi);
*/
public function getD($e, $phi)
{
// Find d using the Extended Euclidian Algorithm: $d = euclid($e, $phi)
// Notice that function euclid($e, $phi) (above) is a user-define function that you need to create,
// so you'll have to call it accordingly as well, i.e., $your_class_instance->euclid($e, $phi) if you put it in your class
return euclid($e, $phi);
} // end getD()
?>
Now let's recap the steps again:
$key = getKey();
OR
$key2 = generateTwoPrime(20000); // you can pass in any number
n = getN($key['p'], $key['q']).
OR
n2 = bcmul($key2['0'], $key2['1']).
This is basically calculating this product of p*q and return its result.
Just return this equation: n = bcmul($key['p'], $key['q']). Very simple!
phi = getPhi(p, q), or more specifically phi = getPhi($key['p'], $key['q']).
OR
phi2 = bcmul($key2[0] - 1, $key2[1] - 1).
This is basically calculating this equation (p - 1)(q - 1) and return its result.
In other words, inside function getPhi(), just return this equation: bcmul($key['p'] - 1, $key['q'] - 1).
For p - 1, q - 1, use bcsub(), for example: bcsub(p, 1) and bcsub(q, 1), or more specifically bcsub($key['p'], 1) and bcsub($key['q'], 1). Very simple!
e = getE(). Use the function getE() shown above.
d = getD(). Use the function getD() shown above.
The argument message in the function RSAEncode() in step 7 below is analogous to the variable $string = THE RED COATS ARE COMING! used in the example earlier. So you'll have to create a function and put the ASCII character numbers code conversion shown earlier in it and call it accordingly. This step 6 is for doing the ASCII character numbers code conversion shown earlier.
encrypted_text = RSAEncode(message, e, n). message is the plain text message you want to encrypt, while e and n are public keys. Function RSAEncode is a user-defined function that you'll need to create, and you can name it any name you want. I named it as RSAEncode. See function rsa() below as a guide.
As a matter of fact, you can create your own RSAEncode(message, e, n) function and call the user-define function rsa() (below) from inside function RSAEncode(message, e, n). As you can see, function rsa() uses this formula: M e mod n. With M = message. Note that you should encode the strings in the variable encrypted_text using bases of your choice, for example: base 16, base32, base64, base92, etc., before sending it over the Internet.
See function rsa() below on how to use step 7 and 8.
decrypt_text = RSADecode(encrypted_text, d, n). encrypted_text is the text message that has been encrypted, while d is the private key and n is the public key. The argument encrypted_text in the function RSADecode() is the result from the encrypted strings in step 7 above. If you encoded the strings encrypted_text in step 7 above, using bases of your choice, for example: base 16, base32, base64, base92, etc., you'll have to decode it (or peel it off) before putting it through the decoding function RSADecode(). In other words, you have to peel off your encoded string variable encrypted_text (from step 7) first in order for the RSA algorithm to correctly doing its job. Function RSADecode is a user-defined function that you'll need to create, and you can name it any name you want. I named it as RSADecode. See function rsa() below as a guide.
As a matter of fact, you can create your own RSADecode(encrypted_text, d, n) function and call the user-define function rsa() (below) from inside function RSADecode(encrypted_text, d, n). As you can see, function rsa() uses this formula: C d mod n. With C = encrypted_text.
See function rsa() below on how to use step 7 and 8
As you can see from the two formulas (M e mod n or C d mod n ) outlined in the eight steps earlier for both encryption and decryption, the syntax for both is the same; and that is, a number M or C raise to the power (e or d) and then mod n. The only difference between the two formulas is the base number (M or C) and the raise power number (e or d).
This means that you can create only one function to calculate both encryption and decryption by passing to this function the appropriate values and the function should return the correct algorithm accordingly.
For example:
/**
* assuming $num is the number to be raised to the power $power
* and then modulo $mod, we can write the function for both
* encryption and decryption like this:
*/
public function rsa($num, $power, $mod)
{
// return the result of the calculation: M e mod n or C d mod n
// just remember to be mindful of the concept called
// "computationally intensive!"
}
/**
* Usage:
*
* $encrypt = rsa($encryption_number, $power_e, $mod_n);
*
* $decrypt = rsa($encrypt, $power_d, $mod_n);
*
* as you can see, you still call the same function, but with different values!
*/
Here is a more detailed example:
/**
* assuming $num is the number to be raised to the power $power
* and then take the modulo $mod, we can write a function for both
* encryption and decryption like this:
*/
public function rsa($num, $power, $mod)
{
// return the result of the calculation: M e mod n or C d mod n
// just remember to be mindful of the concept called "computationally intensive!"
// this is all you need: only one line of code and nothing else!!!
// now after one block of encrypting the text, return it to your calling application so that
// you can encode it using bases: base 16, base32, base64, base92, etc.
return bcpowmod($num, $power, $mod);
}
/**
* Usage:
*
* // in your application that you do your algorithm processing tasks, here is one way to do it.
* // for encryption: first you have to chop your long text strings and use foreach() loop to loop piece by piece
* // and then call the function rsa() above by passing the appropriate values, for example:
*
* $array_of_your_chop_string = str_split($your_long_string, 32); // personally, I prefer 16 due to the "computationally instensive" problem
*
* foreach ($array_of_your_chop_string as $piece)
* {
* // make note of the $piece - you need to convert $piece to a smaller number so that it can be used in the RSA calculation
* $encryption_number = use_the_ordinal_character_number_conversion_shown_earlier_to_convert_$piece_to_a_smaller_number;
*
* // now $encryption_number is a smaller number that can be used and manipulated by the RSA algorithm
* // then call function rsa() to manipulate and calculate the RSA algorithm
*
*
* // make note: you need your 2 public keys: e ($power_e) and n ($mod_n)
* $encrypt = rsa($encryption_number, $power_e, $mod_n);
*
* // now after each block of encrypted text you can encode it using bases, for example: base 16, base32, base64, base92, etc.
* // you need to create a function that converts the base (i.e., base 92) and then call it from here
* // see my tutorial called 'Introduction to Base64 Encryption' on how to create your_long_base_converter_function()
* // you can even use the 'Users Contributed' functions mentioned in the tutorial
*
* $encoded .= your_long_base_converter_function($encrypt, 10, 92) . " "; // notice "a space" between blocks as a delimiter
* }
*
* return $encoded; // now you need to send this $encoded strings to the receiver (or to function rsa()) to decode it
*
*
* // now for decryption: once you got the $encoded string sent to you, you can decode it using function rsa()
* // but first, you have to chop your long $encoded text strings and use foreach() loop to loop piece by piece
*
* $blocks = explode(" ", $encoded); // remember it used a space " " as a block delimiter (above)
*
* foreach ($blocks as $piece)
* {
* // now you have to decode it first using bases, for example: base 16, base32, base64, base92, etc.
* // see my tutorial called 'Introduction to Base64 Encryption' on how to create your_long_base_converter_function()
* // you can even use the 'Users Contributed' functions mentioned in the tutorial
*
* $decode = your_long_base_converter_function($piece, 92, 10); // notice the 92 and 10 switch places
*
* // as you can see, you still call the same function, but with different values!
* // make note also: you need your private key d ($power_d) and your public key n ($mod_n)
* $number = rsa($decode, $power_d, $mod_n); // $number is just a condense number
*
* // now you have to convert the condensed $number into normal ordinary text characters
* $decode_to_normal_text .= use_the_number_to_ordinal_character_number_conversion_shown_earlier_to_convert_$number_back_to_characters;
* }
*
* return $decode_to_normal_text; // this is the decrypted (plain) text you wanted
*
* as you can see, it is very simple to program RSA encryption applications!!!
*/
To be continued!
Implementing RSA encryption in PHP without relying on the OpenSSL extension is achievable using pure PHP libraries like phpseclib. phpseclib is a comprehensive library that provides a pure PHP implementation of various cryptographic algorithms, including RSA.
Here is an example demonstrating basic RSA key generation, encryption, and decryption using phpseclib:
<?php
/**
* RSA key generation
*/
require_once 'vendor/autoload.php'; // Assuming you installed phpseclib via Composer
use phpseclib3\Crypt\RSA;
// 1. Generate RSA Key Pair
// By default, phpseclib generates 2048-bit keys.
// You can specify a different key length if needed, e.g., RSA::createKey(1024)
$privateKey = RSA::createKey();
$publicKey = $privateKey->getPublicKey();
echo "--- RSA Key Pair Generated ---" . PHP_EOL;
echo "Private Key:" . PHP_EOL;
echo $privateKey->toString('PKCS8') . PHP_EOL; // Output private key in PKCS8 format
echo "Public Key:" . PHP_EOL;
echo $publicKey->toString('PKCS8') . PHP_EOL; // Output public key in PKCS8 format
// 2. Data to be encrypted
$data = "This is a secret message to be encrypted.";
echo PHP_EOL . "Original Data: " . $data . PHP_EOL;
// 3. Encrypt the data using the public key
// phpseclib defaults to OAEP padding, which is recommended for security.
$encryptedData = $publicKey->encrypt($data);
echo "Encrypted Data (Base64 encoded for display): " . base64_encode($encryptedData) . PHP_EOL;
// 4. Decrypt the data using the private key
$decryptedData = $privateKey->decrypt($encryptedData);
echo "Decrypted Data: " . $decryptedData . PHP_EOL;
// 5. Verifying the decryption
if ($data === $decryptedData) {
echo "Decryption successful: Original data matches decrypted data." . PHP_EOL;
} else {
echo "Decryption failed: Original data does NOT match decrypted data." . PHP_EOL;
}
?>
Explanation:
require_once 'vendor/autoload.php';: This line assumes you have installed phpseclib using Composer. If not, you would need to manually include the necessary phpseclib files.
use phpseclib3\Crypt\RSA;: This imports the RSA class from phpseclib3.
RSA::createKey();: This static method generates a new RSA private key object. By default, it creates a 2048-bit key.
$privateKey->getPublicKey();: This method extracts the corresponding public key from the generated private key object.
$privateKey->toString('PKCS8'); and $publicKey->toString('PKCS8');: These methods convert the key objects into string representations in PKCS8 format, which is a common standard for key storage.
$publicKey->encrypt($data);: This method encrypts the $data using the public key. phpseclib uses OAEP padding by default, which is a secure padding scheme for RSA encryption.
base64_encode($encryptedData);: The encrypted data is in binary format, so it is base64 encoded for easier display and handling in text-based environments.
$privateKey->decrypt($encryptedData);: This method decrypts the $encryptedData using the private key.
To use this example:
Install Composer if you haven't already.
Create a composer.json file in your project directory with the following content:
/**
* Create a composer.json file
*/
{
"require": {
"phpseclib/phpseclib": "~3.0"
}
}
Run composer install in your terminal to install phpseclib.
Save the provided PHP code as a .php file (e.g., rsa_example.php) in the same directory as your vendor folder.
Execute the script from your terminal: php rsa_example.php.
Implementing RSA in Yii2 without the OpenSSL extension is not recommended for production environments due to potential security vulnerabilities and the complexity of building a pure PHP cryptography library. However, the most widely-used solution for pure PHP RSA, including in Yii2 projects, is the phpseclib library.
The steps below will guide you through implementing RSA encryption and decryption in Yii2 using phpseclib.
Step 1: Install phpseclib with Composer
First, add the phpseclib library to your Yii2 project by running the following command in your project's root directory:
bash
composer require phpseclib/phpseclib:~3.0
Step 2: Generate RSA key pairs
phpseclib can generate the public and private key pair for you. You can do this in a Yii2 console command or a one-off script.
Create a console controller by running yii gii/controller --controllerClass="KeygenController" and add an action to it:
<?php
/**
* Create a controller to generate keys
*/
// controllers/KeygenController.php
namespace app\commands;
use phpseclib3\Crypt\RSA;
use yii\console\Controller;
use yii\helpers\Console;
class KeygenController extends Controller
{
public function actionGenerate()
{
Console::output("Generating new RSA key pair...");
$privateKey = RSA::createKey();
$publicKey = $privateKey->getPublicKey();
// Save keys to files
file_put_contents('@runtime/rsa_private.pem', $privateKey->toString('PKCS8'));
file_put_contents('@runtime/rsa_public.pem', $publicKey->toString('PKCS8'));
Console::output("Keys generated and saved to @runtime/rsa_private.pem and @runtime/rsa_public.pem");
}
}
?>
Run the command to generate the keys:
bash
./yii keygen/generate
This will create rsa_private.pem and rsa_public.pem in your runtime directory.
Step 3: Create a helper class for RSA operations
Using a dedicated helper class makes your code reusable and separates the encryption logic from your application's business logic.
Create a new file components/RsaHelper.php:
<?php
/**
* Creating a RsaHelper class
*/
// components/RsaHelper.php
namespace app\components;
use phpseclib3\Crypt\RSA;
use yii\base\BaseObject;
use yii\base\InvalidConfigException;
class RsaHelper extends BaseObject
{
/** @var string Path to the private key file. */
public $privateKeyFile;
/** @var string Path to the public key file. */
public $publicKeyFile;
private $_privateKey;
private $_publicKey;
public function init()
{
if (!file_exists($this->privateKeyFile) || !file_exists($this->publicKeyFile)) {
throw new InvalidConfigException('RSA key files not found. Generate them with `yii keygen/generate` first.');
}
parent::init();
}
/**
* Loads the private key from the specified file.
* @return RSA\PrivateKey
*/
private function getPrivateKey()
{
if ($this->_privateKey === null) {
$keyData = file_get_contents(\Yii::getAlias($this->privateKeyFile));
$this->_privateKey = RSA::load($keyData);
}
return $this->_privateKey;
}
/**
* Loads the public key from the specified file.
* @return RSA\PublicKey
*/
private function getPublicKey()
{
if ($this->_publicKey === null) {
$keyData = file_get_contents(\Yii::getAlias($this->publicKeyFile));
$this->_publicKey = RSA::load($keyData);
}
return $this->_publicKey;
}
/**
* Encrypts data with the public key.
* @param string $data
* @return string
*/
public function encrypt($data)
{
return $this->getPublicKey()->encrypt($data);
}
/**
* Decrypts data with the private key.
* @param string $data
* @return string
*/
public function decrypt($data)
{
return $this->getPrivateKey()->decrypt($data);
}
}
?>
Step 4: Configure the component in your Yii2 application
Add the new component to your application's configuration file, typically config/web.php or config/main.php.
<?php
/**
* Adding component to application's configuration file
*/
// config/web.php (or config/main.php)
'components' => [
'rsa' => [
'class' => 'app\components\RsaHelper',
'privateKeyFile' => '@runtime/rsa_private.pem',
'publicKeyFile' => '@runtime/rsa_public.pem',
],
// ... other components
],
?>
Step 5: Use the RSA component in your controller
Now you can access the RsaHelper through Yii::$app->rsa and perform encryption and decryption operations.
<?php
/**
* CryptoController
*/
// controllers/CryptoController.php
namespace app\controllers;
use yii\web\Controller;
use Yii;
class CryptoController extends Controller
{
public function actionIndex()
{
$message = "This is a secret message.";
// Encrypt the message using the public key
$encrypted = Yii::$app->rsa->encrypt($message);
// Decrypt the message using the private key
$decrypted = Yii::$app->rsa->decrypt($encrypted);
return $this->renderContent(
'<h1>RSA Example</h1>' .
'<b>Original Message:</b> ' . $message . '<br>' .
'<b>Encrypted Message (Base64):</b> ' . base64_encode($encrypted) . '<br>' .
'<b>Decrypted Message:</b> ' . $decrypted
);
}
}
?>
Security warning: Using RSA without OpenSSL
Performance: Pure PHP implementations like phpseclib can be significantly slower than compiled extensions like OpenSSL, especially for key generation.
Security protocols: The recommended approach for modern RSA encryption is a hybrid method: encrypt the bulk of your data with a fast symmetric algorithm (like AES) and then encrypt the symmetric key with RSA (using OAEP padding for security). phpseclib can help you implement this.
Padding attacks: Never implement textbook RSA without proper padding. phpseclib handles this correctly, but a custom, from-scratch implementation is highly susceptible to attacks.
Key handling: You must store your keys securely. Avoid committing them to version control, and restrict file permissions on the server.
To be continued!
Implementing RSA encryption and decryption in a Yii2 application typically involves using PHP's OpenSSL extension. While you can implement the key generation and encryption/decryption logic directly, using a dedicated library or extension can simplify the process. The xj/yii2-rsa extension is a good example of how this can be achieved.
1. Install the Extension:
First, install the xj/yii2-rsa extension via Composer:
composer require xj/yii2-rsa
2. Generate RSA Key Pairs:
You will need a public and private RSA key pair. You can generate these using OpenSSL:
openssl genrsa -out rsa_private_key.pem 2048
openssl rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem
Store these key files securely within your Yii2 application, for example, in a common/config/ directory.
3. Example Usage in Yii2:
Here's an example of how to use the xj/yii2-rsa extension within a Yii2 controller or component:
<?php
/**
* RsaController
*/
namespace app\controllers;
use Yii;
use yii\web\Controller;
use xj\rsa\RsaPrivate;
use xj\rsa\RsaPublic;
class RsaController extends Controller
{
public function actionEncryptDecrypt()
{
// Define paths to your key files
$privateKeyPath = '@common/config/rsa_private_key.pem';
$publicKeyPath = '@common/config/rsa_public_key.pem';
$originalString = 'This is a secret message for RSA encryption.';
// 1. Private Key Encrypt -> Public Key Decrypt
$privateEncryptor = RsaPrivate::model(Yii::getAlias($privateKeyPath));
$privateEncryptedString = $privateEncryptor->encrypt($originalString);
$publicDecryptor = RsaPublic::model(Yii::getAlias($publicKeyPath));
$publicDecryptedString = $publicDecryptor->decrypt($privateEncryptedString);
echo "Private Encrypt -> Public Decrypt:\n";
echo "Original: " . $originalString . "\n";
echo "Encrypted: " . $privateEncryptedString . "\n";
echo "Decrypted: " . $publicDecryptedString . "\n\n";
// 2. Public Key Encrypt -> Private Key Decrypt
$publicEncryptor = RsaPublic::model(Yii::getAlias($publicKeyPath));
$publicEncryptedString = $publicEncryptor->encrypt($originalString);
$privateDecryptor = RsaPrivate::model(Yii::getAlias($privateKeyPath));
$privateDecryptedString = $privateDecryptor->decrypt($publicEncryptedString);
echo "Public Encrypt -> Private Decrypt:\n";
echo "Original: " . $originalString . "\n";
echo "Encrypted: " . $publicEncryptedString . "\n";
echo "Decrypted: " . $privateDecryptedString . "\n";
return $this->renderContent(''); // Or render a view to display results
}
}
?>
Explanation:
Yii::getAlias() is used to resolve the path to your key files, assuming they are placed in a location accessible by your application.
RsaPrivate::model($privateKeyPath) and RsaPublic::model($publicKeyPath) create instances of the respective RSA classes, initialized with the paths to your key files.
The encrypt() and decrypt() methods are used for the actual encryption and decryption operations.
This example demonstrates both private key encryption/public key decryption (for digital signatures or proving origin) and public key encryption/private key decryption (for secure communication). Remember to handle errors and potential exceptions appropriately in a production environment.
To be continued!
In my other tutorial called Introduction to RSA Encryption, I layout an extensive description about the RSA encryption scheme. The RSA encryption scheme is an asymetric encryption scheme where you have a public key and a private key and both the sender and receiver would use different keys to encrypt and decrypt the message.
On the other hand, the RC4 encryption scheme is a symetric encryption scheme where both the sender and receiver would use the same key to encrypt and decrypt the message.
The RC4 encryption scheme was adopted and certified by the National Institute of Standards and Technology (or NIST) for safety uses for other uses that don't require military grade encryption like the RSA encryption scheme.
In other words, the RSA encryption scheme is a military grade encription scheme that is being used widely in banking applications and other top secret applications. The RC4 encryption scheme is an encryption scheme that is targeted for applications that do not require military grade encryption applications.
In a symetric encryption like the RC4, both the sender and receiver would use the same key to encrypt and decrypt the message. There is only one key, and each time a sender or receiver decides to change it and create a new one, they both need to meet again to create the key and exchange it among themselves.
This is analogous to a typical key you used on a daily basis where you need the same key to lock and unlock your doors.
This method is very secure as long as the key is not fallen into the wrong hands. And the same thing can be said about your regular key: If thieves don't get a hold of your key, they can't get in your house and steal your stuffs.
But the drawback for this method is that it is very inconvenient to both parties (sender/receiver) since both parties have to create the key and exchange it among themselves, unlike the RSA encryption scheme where you don't need to meet the other parties and exchange the key.
In the RSA encryption scheme, the sender does not need to get the key from the receiver. The sender can just obtain the public key that is available to the public because of the receiver made the key very public to anyone, including hackers. The sender can be far away across the occeans and never have to meet or know the receiver to exchange the key. This makes the RSA encryption scheme very powerful and popular all over the world -- not to mention that it is also a military grade encryption scheme as well.
In the asymetric encryption system, particularly the RSA encryption system, it has both a public and a private key and only one party (the receiver) needs to create the keys and neither need to meet with each other in order to exchange the keys securely.
In 1977, a group of three researchers at MIT developed an asymetric encryption algorithm for public-key cryptography known by its acronym as the RSA, which stands for the inventors' last names: R being Ron Rivest, S being Adi Shamir, and A being Leonard Adleman.
In cryptography, RSA encryption system is an asymetric encryption algorithm for public-key cryptography. It was the first algorithm known to be suitable for signing as well as encryption, and one of the first great advances in public key cryptography. RSA is widely used in electronic commerce protocols, and is believed to be secure given sufficiently long keys and the use of up-to-date implementations.
RSA involves a public key and a private key. The public key can be known to everyone and is used for encrypting messages. Messages encrypted with the public key can only be decrypted using the private key.
In this tutorial, I'm going to show you how to use a subset of the RSA encryption system called the RC4 cryptography (Rivest Cipher version 4). RC4 is an encryption algorithm that was created by Ronald Rivest of the RSA Security fame. He created this subset alone (by himself), unlike the RSA, which he and two others created together. The RC4 is used in WEP (or Wireless Encryption Protocal) and WPA (or Wireless Portable Adapter), which are encryption protocols commonly used on wireless routers.
Some notable uses of RC4 are implemented in Microsoft Excel, Adobe's Acrobat 2.0 (1994), and BitTorrent clients and as well as the following:
For more information about the ASCII code check out the Web on the topic of ASCII code or see the following link. In the following link, look for code under the title heading "BIN" for your particular character. ASCII Code
p = 01110000
w = 01110111
d = 01100100
1 = 00110001
2 = 00110010
The specification also gives the generic code example that we can adapt to whatever programming language we choose, and it is listed below.
Here is an illustration to accompany the generic code example specification:
// For key handling
for i from 0 to 255
S[i] := i
endfor
j := 0
for i from 0 to 255
j := (j + S[i] + key[i mod keylength]) mod 256
// swap the value of i into j and j into i and
// it looks like this:
// x = s[i];
// s[i] = s[j];
// s[j] = x;
// here it is
swap(S[i], S[j])
endfor
//The pseudo-random generation algorithm (PRGA).
i := 0
j := 0
while GeneratingOutput:
i := (i + 1) mod 256
j := (j + S[i]) mod 256
// swap the value of i into j and j into i and
// it looks like this:
// x = s[i];
// s[i] = s[j];
// s[j] = x;
swap(S[i], S[j])
output S[(S[i] + S[j]) mod 256]
endwhile
<?php
class RC4Encryption
{
public function rc4($key, $str)
{
$s = array();
for ($i = 0; $i < 256; $i++)
{
$s[$i] = $i;
}
$j = 0;
for ($i = 0; $i < 256; $i++)
{
$j = ($j + $s[$i] +
ord($key[$i % strlen($key)])) % 256;
$x = $s[$i];
$s[$i] = $s[$j];
$s[$j] = $x;
}
$i = 0;
$j = 0;
$res = '';
for ($y = 0; $y < strlen($str); $y++)
{
$i = ($i + 1) % 256;
$j = ($j + $s[$i]) % 256;
$x = $s[$i];
$s[$i] = $s[$j];
$s[$j] = $x;
// could it be this instead ????
// $res.= chr(ord($str[$y]) ^ $s[($s[$i] + $s[$j]) % 256]);
$res .= $str[$y]^ chr($s[($s[$i] + $s[$j]) % 256]);
}
return $res;
}
}// end class RC4Encryption
?>
/*
* RC4 symmetric cipher encryption/decryption
*
* @param string key - secret key for encryption/decryption
* @param string str - string to be encrypted/decrypted
* @return string
*/
function rc4(key, str)
{
var s = [], j = 0, x, res = '';
for (var i = 0; i < 256; i++)
{
s[i] = i;
}
for (i = 0; i < 256; i++)
{
j = (j + s[i] + key.charCodeAt(i % key.length)) % 256;
x = s[i];
s[i] = s[j];
s[j] = x;
}
i = 0;
j = 0;
for (var y = 0; y < str.length; y++)
{
i = (i + 1) % 256;
j = (j + s[i]) % 256;
x = s[i];
s[i] = s[j];
s[j] = x;
res += String.fromCharCode(str.charCodeAt(y)^ s[(s[i] +
s[j]) % 256]);
}
return res;
}
Now that we have a class for the server-side in PHP that returns the encrypted and decrypted messages and a client-side algorithm script in Javascript, we can use both the client- and server-side scripts in any applications to process the encrypted and decrypted messages.
Make note: function rc4() does both encrypting and decrypting the message. Yes, it seems very odd that one function returns both the encryption and decryption algorithms. Nonetheless, it does that both using the same key and the same algorithm. Very odd, indeed!
First of all, you may only need to use one of the scripts above; for example, you may choose to use the server-side PHP code but not the client-side Javascript code, or vice versa, depending on your application logic.
So, yes, you don't need to use both of the client-side and server-side code above at all: they can work independently of one another.
Depending on your application logic, you can use the server-side algorithm only or in conjunction with the client-side algorithm. They are provided here for those of you who need to work with both the client- and server-side applications in situation where you want to encrypt form data when users enter them on the input boxes, e.g., username and password, and encrypt those data before sending them to the server-side script for processing.
Once arrived at the server-side script the server-side script can decrypt the data using the server-side algorithm. So this ensures that no hackers can intercept the data while intransition.
Speaking of application logic and username and password, you can use this function rc4() to encrypt and decrypt RSA keys when you create the two primes (p, q). It is a very convenient function that is suiteable for such tasks.
If you need to use only one of the versions, here is all you need to do:
// PHP usage
// supply your own secret key
// you should use function rc4() to encrypt and decrypt this key.
// you should create keys, encrypt them and store them in a db or file.
// when you need to use them, retrieve them, decrypt them, and then
// use them like in here!
// decrypt the key before using it!
$key = "redalerttherussiansarecoming";
// the content to be encrypted
$plaintext = "Hello World!";
// encrypt the content by calling the rc4()
$ciphertext = rc4($key, $plaintext);
// from here, you can do whatever you wish with the cipher.
// now here is where you decrypt the content:
// you pass the same key used to encrypt and also the cipher text
$decrypted = rc4($key, $ciphertext);
// from here, you can do whatever you wish with the decipher. That is it!
echo $decrypted . " = " . $plaintext . "\n";
// Javascript usage
// supply your own secret key
var key = "0123456789abcdef"; // or in phrase: theskyisblue
// the content to be encrypted.
// usually getting from the input boxes, e.g., username, password
// once arrives in the server script (php) and decrypted,
// use explode('&', decryptedFromClient)
var plaintext = "username&password";
// encrypt the content by calling the rc4()
var ciphertext = rc4(key, plaintext);
// from here, you can do whatever you wish with the cipher
// now here is where you decrypt the content
// you pass the same key used to encrypt and also the cipher text
var decrypted = rc4(key, ciphertext);
// from here, you can do whatever you wish with the decipher
document.out.write(decrypted + " = " + plaintext + "\n");
<script type="javascript">
function getxmlHttp()
{
var xmlHttp = null;
// if the user's browser is FireFox, Safari, and
// for all other non-Microsoft browsers.
if (window.XMLHttpRequest)
{
// FireFox, Safari, and for all other browsers.
xmlHttp = new XMLHttpRequest();
if (typeof xmlhttp.overrideMimeType != 'undefined')
{
xmlHttp.overrideMimeType('text/xml'); // Or anything else
}
}
// else if all Microsoft browsers
else if (window.ActiveXObject)
{
// MSIE
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
}
else
{
// No known browsers -- consider aborting the application
alert("unknown browser");
}
return xmlHttp;
}
</script>
<form method="post" action="POST">
<input type="text" name="name" value=""
onChange="getInfo()">
<input type="text" name="email" value=""
onChange="getInfo()">
<input type="text" name="content" value=""
onChange="getInfo()">
<input type="text" name="username" value=""
onChange="getInfo()">
<input type="password" name="password" value=""
onChange="getInfo()">
<!-- make sure that you encrypt the key and password using ->
<!-- Javascript function listed earlier ->
<!-- see function getInfo() listed later ->
<input type="password" name="key" value=""
onChange="getInfo()">
<input type="submit" name="submit" value="Submit"
onClick="getInfo();">
</form>
<script type="javascript">
function getInfo()
{
/**
* notice that the following values are obtained from the form,
* in your local machine and no values are travelled outside of
* of your local server/machine and therefore no security issue
* is in harm's way.
*/
var name = document.getElementById("name").value;
var email = document.getElementById("email").value;
var content = document.getElementById("content").value;
var username = document.getElementById("username").value;
var password = document.getElementById("password").value;
var key = document.getElementById("key").value;
//concatenate the name/value pairs
var str = "name=" + escape(name) + "&email=" +
escape(email) + "&content=" + escape(content) +
"&username=" + escape(username) +
"&password=" + escape(password) +
"&key=" + escape(key);
// now you need to encrypt it (str)
ciphertext = rc4(key, str);
var xml_obj = getxmlHttp(); // create an Ajax object
// set up a url of the server-side script where to
// send the encrypted str to (url) as a GET method!
// alternatively, you use post method as well, but modify it accordingly!
var url = "/Encryption/server_side.php?cipher=" + ciphertext;
var isNS4 = (document.layers)?true:false;
var isNS6 = document.getElementById &&
(navigator.appName == "Netscape")?true:false;
if (!(isNS4 || isNS6 || "Macintosh" == "Windows"))
{
if (event.keyCode == 13)
{
// we do a "GET" to the server
xml_obj.open("GET", url, true);
// no POST to send to server, we did a "GET" instead
xml_obj.send(null);
xml_obj.onreadystatechange = function()
{
if (xml_obj.readyState != 4)
return; // do nothing ... not ready state yet
if (xml_obj.status != 200)
{
// do nothing ... handle request failure here...
return;
}
// read the response from server-side,
// which contains a ciphertext and decrypt it also
// noitice that xml_obj.responseText contains a ciphertext
// while response contains the decoded plain text
var response = rc4(key, xml_obj.responseText);
var piece = response.split("|"));
// for each array variable piece call a function outResponse()
// passing two arguments: item, index
piece.forEach(outResponse);
}
}
if (event.keyCode < 45 || event.keyCode > 57)
event.returnValue = false;
}
}
function outResponse(item, index)
{
document.out.write("key: " + index + " = value: " + item);
}
</script>
<?php
include_once "rc4.php";
$obj = new RC4Encryption();
//get a key from the database
$key = '0123456789abcdef';
$plaintext = array();
if (isset($_GET['cipher']))
{
$encryptedFromClient = $_GET['cipher'];
$decryptedFromClient = $obj->rc4($key, $encryptedFromClient);
$plaintext = explode('&', $decryptedFromClient);
foreach ($plaintext as $k => $v)
{
// you can do something with $v, such as save it in db,
// but here, we'll just format it and send it back to client
$str .= $v . '|';
}
//let the client know we're sending back plain text data (not XML)
header("Content-Type: text/plain");
$encryptedToClient = $obj->rc4($key, $str);
//send it back to the client
echo $encryptedToClient;
}
?>
This script (server_side.php) grabs the incoming http request content using a "GET" variable ($_GET['cipher']) and decrypts it using the function rc4(). It then chops the content into array values (key => value) and then formats the content using "|" as the array values delimiter. It then encrypts and sends the content back to the client. That's it!
The goal of the OpenSSL is to generate keys, certificates, and encrypt/decrypt messages and do other things related to encryption.
However, as often the case, you can do all these things with other tools as well. In later sections, we'll use PHP to do all these things to make our lives easier since using OpenSSL tool is not the easiest thing to do.
For those of you who want to use OpenSSL tool to accomplish the tasks, read on.
Check out the official OpenSSL docs for explanations of the standard commands:
OpenSSL Cryptography and SSL/TLS ToolkitOpenSSL is a cryptography toolkit implementing the Secure Sockets Layer (SSL v2/v3) and Transport Layer Security (TLS v1) network protocols and related cryptography standards required by them.
The openssl program is a command line tool for using the various cryptography functions of OpenSSL's crypto library from the shell to generate the following tasks.
When a client (browser) requests a secure connection to a server, the server, in turn, requests specific protocol information to figure out which types of cryptographic security the client can support. Once it determines the most secure option, the following takes place:
SSL and TLS are two of many security protocols used to accomplish these steps. To implement these protocols, we need software like OpenSSL.
You'll come across tons of abbreviations in this guide and other OpenSSL tutorials. For quick reference, here is a short list of some terms you might encounter:
To use OpenSSL, follow these steps:
Download the source code for most platforms from the official OpenSSL website.
Download the source code for OpenSSLIf you need a windows distribution, Shining Light Productions has a good one although there are plenty of alternatives. For simplicity and for Windows OS users, I recommend using Shining Light Production, which you can download it below. In other words, you don't need to download the OPENSSL binaries from the OPENSSL website listed above, but instead, you can download it from the Shining Light Project listed below:
Download the Shining Light binaries insteadYou need to download the Shining Light and extract it and install it by just following the installation prompts.
In the Shining Light download page, choose the 64-bit version -- the first one in the list for a 64-bit -- by clicking on the EXE link under the Win64 OpenSSL v1.1.1g Light version (as of this writing), and extract it and install it on your system by just following the easy installation prompts.
Once everything is successfully installed, you can begin to use the OpenSSL commandline tool to generate keys, certificates, and countless other things.
For this tutorial, let's experimenting with the OpenSSL command line tool to get a better feel for it.
First, you need to open your command line prompt tool. For Windows OS, you can use the default command line tool that comes with the Windows Operating System by typing 'cmd' in the Windows search box at the lower left hand corner, and press enter.
A command line window that looks like the one below opens up and ready for your use.

As you can see from the Windows command line tool above, you can type any command to execute it.
For me, I installed my Shining Light tool in the directory called C:\Users\Home\. So the Shining Light comes with a folder called 'OpenSSL-Win64' if you download the 64-bit version.
So you need to navigate to the directory that contains the Shining Light binaries. For me, it's C:\Users\Home\OpenSSL-Win64\bin\openssl.
Notice the last entry: openssl. This is the executable file name and you need to execute this openssl.exe program.
Since the command prompt points to my default directory C:\Users\Home\, I need to change the default directory to the directory where it can find the Shining Light binaries, which resides in a directory called bin.
So at C:\Users\Home\ default directory, I can navigate to the binaries by changing the directory level by level by changing the directory level one at a time like this:
C:\Users\Home>cd OpenSSL-Win64 and press enter.
Now it should point to the current directory of:
C:\Users\Home\OpenSSL-Win64>
Now again you need to change the directory to a higher level -- namely the 'bin' directory -- by doing this:
C:\Users\Home\OpenSSL-Win64>cd bin and press enter.
Now it should point to the current directory of 'bin':
C:\Users\Home\OpenSSL-Win64\bin>
Now at the current directory of 'bin', you can enter the 'openssl' executable program and press enter. For example:
C:\Users\Home\OpenSSL-Win64\bin>openssl and press enter.
This will will point the current directory to the OpenSSL binaries that you can basically execute.
Now the command prompt will show this: OpenSSL>
And the cursor should be blinking and waiting for you to type something. Type a command and press enter.
Now you can try to type a command at the above prompt to see the result.
Let's try to see what the current version of the OpenSSL is by typing the following and press enter:
OpenSSL>version
Now it should say something like this:
OpenSSL 1.1.1g 21 April 2020.
If you need to know what type of commands you can use to execute, just type 'help' and press enter.
To close the Windows command line tool and exit the program, just type 'exit' at the prompt and press enter.
Let's try to generate the RSA encryption keys by typing the following and press enter:
OpenSSL>genrsa -out mykey.pem 2048
Now the tool generates an RSA private key, 2048 bit long modulus (2 primes)
You should now have a file called mykey.pem containing a private key in a folder called PEM. In the PEM folder, there should be a lot of stuffs that belong to OpenSSL for OpenSSL to use. But you only care about your private key that you generate, which in this case, mykey.pem.
See PEM folder in the directory that look like this: C:\Users\Home\OpenSSL-Win64\bin\PEM.
Notice that as the file's name suggests, the private key is coded using the Privacy Enhanced Email, or PEM, standard.
To encrypt our private key, we use the following code and press enter.
The command reads in from a file called mykey.pem using des3 as an algorithm and output the encrypted key to a file name my-encrypt-key.pem. Note that the minus sign ('-') in -des3 is part of the command and not part of the algorithm.
OpenSSL>rsa -in mykey.pem -des3 -out my-encrypt-key.pem
[
You can use any algorithm in place of the des3. To find the available algorithms, type in the command prompt: help.
Look under the category: Cipher commands. For example, aes-128-cbc, aes-256-cbc, rc4, etc.
]
Now the OpenSSL tool will display a message saying:
Writing RSA key
Enter PEM pass phrase
While showing a blinking cursor waiting for you to enter the password.
After you type your password and press enter, it will display the message:
Verifying - Enter PEM pass phrase
You need to enter the exact password you entered the first prompt and press enter.
If the passwords are verified, the tool will encrypt the key without displaying any message. It will display a command prompt for you to enter another command. For example:
OpenSSL>
And the cursor should be blinking and waiting for you to type something.
On the other hand, if the passwords are not verified, the tool will display the error message, telling you what's wrong with your entry.
If you entered the correct password for both entries, you should see a file name called my-encrypt-key.pem in the the PEM folder along with the already file mykey.pem that was created earlier.
//
To be continued!
Please check these out:
Steganography Steganography: How to Hide Top-Secret Data in Photos Steganography: Secrets Hidden in ImagesSteganography is an encryption method that uses images to embed messages. It is an encryption method that encodes text into images.
In the dictionary, the definition of steganography is the art of hiding messages in an image.
If you had watched a TV episode series called The FBI Declassified on CBS, which aired on October 13, 2020 where the FBI counter-surveillanced the ten Russian spies that took place from 2004 to 2009, you would know that the Russian's method of hiding messages was the steganography (encode text into image) method of encryption.
This is a great way to send a secret message to a friend without drawing attention to it (as the Russians have used to their advantage in their spy ring during the surveilance by the FBI).
Compare this method to simply sending someone an encrypted piece of text using the RSA, RC4, or any of the other algorithms and you'll draw attention to you immediately.
No matter how strong the encryption method is, if someone is monitoring the communication, they'll find it highly suspicious.
With steganography, no one is aware of what you're doing covertly.
The fact that digital images are just streams of bytes like any other file makes them a particularly effective medium for concealing secret text and other data.
When they open a picture on a device, i.e, mobile phone or laptop, few people ever have reason to look beyond the visual presentation displayed to what lies hidden inside the .jpg, .png, .bmp or other image file format.
Popular algorithms include simple least significant bit (LSB) steganography, group-parity steganography, and matrix embedding.
To understand how image steganography works, let's take a look at some basic ways you can hide text in an image file.
A Work-in-progress! To be continued!
By the way, the slang word for steganography is stego!
Also a message is sometimes called a payload!
To embed the message, some pixels in the cover image must be modified by an embedding operation so that the resulting stego image conveys the message bits.
Two popular operations are LSB replacement and LSB matching.
In LSB replacement, odd pixels are decremented and even pixels are incremented.
In LSB matching, pixels are either incremented or decremented as necessary.
By storing the message in the LSBs, the resulting stego image looks similar to the cover image, making it difficult to detect by steganalysis detectors. Despite being careful, if the number of changes is sufficiently large, it is still possible to detect stego images as suggested by the square root law of steganographic capacity (Ker, 2007, Filler et al., 2009, Ker, 2009).
Once a stego image is detected, further processing is needed to extract the hidden message, which is inherently a difficult problem. One approach is to search for the embedding key (Fridrich et al., 2004).
This technique is applicable when the key space is small and details about the embedding software are known. The advantage is that once the key is found, the hidden message can be extracted readily.
An alternative approach that may lead to the eventual message extraction is to locate the message using a number of stego images where each stego image has the payload at the same locations (Ker, 2008, Ker and Lubenko, 2009, Quach, 2011a, Quach, 2011b, Quach, 2012, Quach, 2014).
This could happen if the naive steganographer reuses the embedding key and the stego images are the same size.
As an example, the steganographer takes several pictures using his digital camera and then embeds messages into these pictures using the same password, e.g., embedding key. Message location (or sometimes called payload location) can be used in this scenario.
Message location can be effective against simple LSB steganography as well as group-parity steganography. Message location algorithms generally rely on computing the residuals of pixels indicating whether they have been modified in the embedding process.
Payload location, however, can only reveal the message bits; the messages themselves remain hidden as we do not know the logical order of the located payload. In order to extract the messages, we need to establish the correct order on the located payload.
The current work addresses this fundamental problem. Specifically, we show that if the size of the payload in each stego image is not fixed, the expected mean residuals impose the correct logical order on the located payload.
In particular, the expected mean residual of logical payload bit i is strictly greater than the expected mean residual of logical payload bit j for i < j. The hidden messages, therefore, can be obtained by ordering the located payload in descending mean residual.
Following a brief overview of steganography and payload location in Section Background, our main result is presented in Section Message extraction. Experimental results to further support our analysis are presented in Section Experiments. Concluding thoughts are provided in Section Discussion and conclusion.
In simple LSB steganography, each payload bit is determined by a single pixel. Given cover image c = (c1,..., cn)2 and message m = (m1, m2,..., mm), where and m = n, a naive algorithm would use the pixels in their natural order to embed m to produce stego image s = s1, s2,..., sn so that LSB(s1) = m1, LSB(s2) = m2, etc., where LSB(.) returns the least significant bit.
This is not recommended due to the fact that the introduced stego noise is concentrated in the first m pixels of the stego image, possibly making it easier to detect.
More importantly, the message can be extracted by examining the LSBs of the first m pixels. To overcome these undesirable characteristics, a key is often used in the embedding process to distribute the payload over the entire image. Both embedding processes are illustrated in Fig. 1.
To be continued!
Please check these out:
Base16, Base32, and Base64 Data Encodings base64_encode - Encodes data with MIME base64 base64_decode - Decodes data encoded with MIME base64 What is Base64?Base64 is a method to convert ordinary text characters you type on your keyword to a binary form that a computer can understand. However, despite the title of this tutorial, it is not an encryption method, but rather, it is an encode method used to encode (or convert) normal text characters into a binary form that a machine can understand.
The base64 encoding is designed to make binary data survive transport through transport layers that are not 8-bit clean.
Why is the need to convert normal text characters to a binary form?
Rather than spending time explaining it, I'll refer to this excellent explanation on the Web:
What is base 64 encoding used for?In the RSA encryption tutorial, you can make it even more secure and robust by encoding the RSA's encrypted message with other bases such as base64, base10, base16, base32 or other bases like base26, base62, base92, etc.
As a matter of fact, wise guys like to encode their RSA encrypted text with other bases to make their RSA encryption algorithm even more secure.
Note that you have to keep the base that you're using a secret; otherwise, hackers can use your base to convert back to your original encrypted text.
In other words, don't let hackers see your function that converts your base.
You don't need to be too secret with your base (or function that converts your base), just keep it out of sight and don't advertise to the public like you do with your public keys.
Even if hackers got a hold of your base, they still have to break your RSA encryption algorithm as well. So there is no need to worry about being too secrecy about your base.
Remember that the RSA encryption algorithm is your heart and soul of your encryption!
So don't worry too much about hackers getting a hold of your base, they still need to break your RSA encryption algorithm, too.
You can use the following code provided by PHP's user contributed forum notes:
base_convert: Users contributed forum notesHere is a base 92
/**
* Returns a string containing number represented in base $tobase.
* The base in which number is given is specified in $frombase.
*
* Both $frombase and $tobase have to be between 2 and 92, inclusive
*
* Digits in numbers with a base higher than 10 will be represented with
* the letters a-z, with 'a' meaning 10, 'b' meaning 11 and 'z' meaning 35.
*
* The case of the letters doesn't matter, i.e.,
* number is interpreted case-insensitively.
*
* from Stackoverflow:
*
* base64_encode(1234) = "MTIzNA=="
* base64_convert(1234) = "TS" // if the base64_convert function existed
* base64 encoding breaks the input up into groups of 3 bytes (3*8 = 24 bits),
* then converts each sub-segment of 6 bits (2 6 = 64, hence "base64") to
* the corresponding base64 character:
*
* values are "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
*
* where A = 0, / = 63
*
* In our example, base64_encode() treats "1234" as a string of 4 characters,
* not as an integer (because base64_encode() does not operate on integers).
*/
public function longBaseEncode($numstring, $frombase, $tobase)
{
// Converts a long integer (passed as a string) to/from any base from 2 to 92
// Notice that the following code is one continuous line!
// It is broken into two lines to fit the display area!
$char = "0123456789abcdefghijklmnopqrstuvwxyz
ABCDEFGHIJKLMNOPQRSTUVWXYZ_-+=!@#$%^*(){[}]|:,.?/`~&';\"\\";
$fromstring = substr($char, 0, $frombase);
$tostring = substr($char, 0, $tobase);
$length = strlen($numstring);
$result = '';
for ($i = 0; $i < $length; $i++)
{
// Array and string offset access syntax with curly braces is deprecated
// $number[$i] = strpos($fromstring, $numstring{$i});
// so use [] instead of {}
$number[$i] = strpos($fromstring, $numstring[$i]);
}
do
{
$divide = 0;
$newlen = 0;
for ($i = 0; $i < $length; $i++)
{
$divide = $divide * $frombase + $number[$i];
if ($divide >= $tobase)
{
$number[$newlen++] = (int)($divide / $tobase);
$divide = $divide % $tobase;
}
elseif ($newlen > 0)
{
$number[$newlen++] = 0;
}
} // end for
$length = $newlen;
// Array and string offset access syntax with curly braces is deprecated
// $result = $tostring{$divide} . $result;
// so use [] instead of {}
$result = $tostring[$divide] . $result;
} // end do
while ($newlen != 0);
return $result;
} // end function longBaseEncode()
/**
* Usage:
*
* first, you need to break your message into small pieces that
* looks like this one piece:
*
* 'THE RED COATS ARE COMING!'
*
* see the "bonus" materials in the "RSA" tutorial.
*
* next, once you have the pieces, you can use loops to encrypt your pieces
* and at the same time, you can encode your pieces using this 'longBaseEncode()'
*
* assuming:
*
* $piece = 'THE RED COATS ARE COMING!';
*
* make sure that $piece has been encrypted before
* wrapping 'longBaseEncode()' around it!
*
* for example:
*
* wrapping longBaseEncode() around $piece to make it even more secure:
*
* $ciphertext = longBaseEncode($piece, 10, 92) . " ";
*
* notice that $ciphertext should contains chunks of encrypted text seperated
* each chunk with a blank " ".
*
* so it should looks like this:
*
* $ciphertext = 'a65xa07491k f5zyfpvbo76g33 3o47re02jzqisvio rgo9la0 ....'
*
* make note of the space between chunks!
*/
You can use some of the "User Contributed" code examples shown in the link mentioned earlier to encode your RSA encrypted text.
There you have it!
Go at it!
To be continued!
Technology is like fashion: it has trends!
Just a few years ago starting right around 2014 and beyond the trend in technology was about drone delivery - delivering everything like packages to residential households in cities and rural areas as well as delivering lifesaving medicines to hard to reach remote corner of the world.
Remember they were saying that you can order packages from Amazon and Amazon was going to air drop your packages in your backyard without you being present while you are still at work in your office away from home?
Has it happened yet?
The jury is still out on this one!
Now the year is 2018 and a hot new technology trend is called autonomous self-driving vehicle. Yes, autonomous self-driving vehicle is all the rage these days and it reminds me of the rage that Ajax garnered right around 2004-5 as if it was the second coming of the birth of the internet.
Yes, Ajax was all the rage for quite some time in those days and continued for much of the first half of the millenial decade (up to 2015).
Now (2018 and beyond) all the rage is about autonomous self-driving vehicle and it catches people's imagination all over the world these days and therefore I thought it's a good time to take a look at autonomous sphere and shed some lights on it. Sort of a beginner's guide to autonomous self-driving vehicle technology.
Like drone technology which requires a government body to regulate how it is operated: that is, drones operations is like airplane operations where safety issues are paramount above all else; autonomous self-driving vehicle also requires a government body to regulate how it is operated to ensure that safety issues are fully tested and certified.
The SAE International is the professional association of automotive engineers formed by the automotive industry of the world to standardize the way automotive function in a standardize way.
The acronym SAE is derived from the association name: Society of Automotive Engineers.
The SAE is a group of automotive engineers who specialize in developing automotive technologies, such as air bags, elastic seat belts, and many other essential automotive products. Since 2005, the SAE has been focusing its attention on autonomous self-driving vehicle technologies.
They adopted the following guideline for the automotive industry to follow:
What do terms like "Level 4" and "Level 5" mean?
Here's the complete guide.
What does it mean when someone refers to "Level 4" or "Level 5" self-driving?
What are the levels, and who decides which systems qualify?
The "levels" are taken from a framework established by SAE International -- SAE is the acronym for Society of Automotive Engineers, the professional association of automotive engineers, as a shorthand to describe how far a particular system goes in automating the task of driving a vehicle. The SAE's framework has been widely adopted by (government) regulators, engineers, and automakers -- and by investors, too.
The SAE's framework describes six levels of vehicle automation, ranging from no automation at all -- an old-school car -- to fully automated, meaning a system that can drive at least as well as a skilled human in any situation.
It's very important for investors looking at companies in the self-driving space to understand what is meant by the various levels, who decides what level to assign to a given system, and the differences between the levels -- particularly as they get more advanced. (I'll tell you a secret up front: Sometimes, systems described as "self-driving" really aren't.)
It hasn't always been easy to make sense of this framework. As you'd expect from a society of automotive engineers, the SAE's own descriptions of the levels are jargony and a little hard for nonexperts to parse. But for the most part, they make sense when explained in plain English -- and that's what you'll find in the following.
What is autonomous driving?
First and foremost, an "autonomous driving" system is one that allows a vehicle to drive safely on public roads without human involvement. Terms like "automated driving," "driverless vehicle," and "self-driving car" are all describing the same technology: A computer "brain" and sensors that can drive a vehicle in place of a human, at least under some circumstances.
Here are a few key things to keep in mind as we dig into the world of automated driving systems:
Advanced driver-assist and driverless systems rely on several types of sensors, including cameras, radar, and lidar (a sensor that uses invisible laser beams to precisely measure distances) to help the vehicle's computer "brain" understand where the vehicle is relative to its surroundings.
The number of sensors used, the amount of computing power required for the "brain," and the overall cost of the system all typically increase as the level of automation increases.
Self-driving systems are a form of artificial intelligence. They generally incorporate machine learning, meaning algorithms that can adjust themselves and improve their effectiveness as more data is acquired.
Fully driverless systems acquire vast amounts of data as they travel from place to place and encounter new traffic situations. The individual vehicles' systems typically share that data with a remote data center, which updates all of the vehicles using the system with lessons learned. This process is called fleet learning.
There's one more thing to know, and it's very important to keep in mind as you assess claims about particular systems:
The level assigned to any given system is assigned by its manufacturer. As of right now, there is no independent or government agency certifying a given system as Level 3 or Level 4 or whatever. Until that changes, the levels are best thought of as a manufacturer's claim: They might be a bit optimistic, so drive carefully.
If you'd like to dig deeper, you'll find a comprehensive overview of driverless-vehicle systems by Googling SAE autonomous driving vehicle.
For now, let's see what these levels mean:
Level 0: No automation.
Level 1: A little automation.
Level 2: Control of steering or brakes, but not both, under limited circumstances.
Level 3: More automation, but not self-driving.
Level 4: True self-driving, but under limited circumstances.
Level 5: Full self-driving with no limitations.
The SAE's framework begins with Level 0: No automation. The human driver is responsible for 100% of what the SAE refers to as "the dynamic driving task," meaning the work of actually driving the vehicle on an ongoing basis. (Keep that word "ongoing" in your mind as you read on -- it's a key part of how the SAE defines automation.)
Level 0 isn't that hard to understand, but even here there are some nuances. Probably the most important point is this: There are plenty of modern cars with driver-assistance features that still qualify as Level 0.
For instance, antilock brakes don't count as automation because the human still has to step on the brake pedal. Even systems that automate a momentary task -- like the automatic emergency braking systems found on some new cars -- don't count as automation for our purposes, because they don't automate the "dynamic driving task" on -- you guessed it -- an ongoing basis.
The takeaway: While your grandfather's old Buick is certainly a Level 0 vehicle, so are many modern cars that are equipped with what we think of as "driver-assist" features.
The SAE defines a Level 1 system as one that provides either steering control or acceleration-and-braking control on an ongoing basis -- but only under limited, specific circumstances.
What does that mean?
Here's an example using technology that's probably familiar to you.
Aside from very basic entry-level model, most cars made in recent years have a cruise-control system. You've almost certainly used one, but if you haven't, the principle is simple: Accelerate to a desired speed, activate the cruise control, and the system will hold the vehicle at that speed, even up and down hills, after you take your foot off of the accelerator pedal.
That doesn't count as "automation" in the SAE's framework, because the dynamic part of the driving task isn't automated: The human still has to be ready to hit the brakes (and deactivate the system) if there's slower traffic ahead.
In recent years, automakers have begun offering more advanced cruise-control systems, so-called adaptive cruise control. Adaptive cruise control systems are smarter: They use radar to keep your car at a safe distance behind the vehicle ahead. If the car ahead slows, the system automatically slows your car as well in an effort to maintain a safe distance.
With adaptive cruise control, one part of the dynamic driving task -- controlling acceleration and brakes -- is automated. Of course, it's only automated under specific circumstances, namely when you turn the system on while driving on the highway. But that's sufficient to lift an adaptive cruise-control system into Level 1.
Level 2 is "partial automation." It's for driver-assistance systems that provide both steering and acceleration-and-braking control, but again, only under limited circumstances. If the human driver has to intervene regularly -- for instance, when the car is exiting a highway -- then it's probably a Level 2 system. Importantly, it's not "self-driving," even if it kinda-sorta seems like the vehicle is driving itself.
That can make understanding Level 2 a little tricky. Let's take a closer look.
Level 2 can sometimes seem like self-driving, but it isn't Tesla's (NASDAQ: TSLA) Autopilot and General Motors' (NYSE: GM) Super Cruise, both of which can accelerate, brake, and steer under many (but not all) circumstances, can certainly deliver an experience that seems like "self-driving."
But there's a reason that GM and (usually) Tesla are very careful not to describe them as full self-driving systems in their current forms: With both, the human driver needs to be alert and ready to take over the driving task on very short notice -- more or less instantly.
That's a critical distinction. If a human driver is needed on short notice, then a system shouldn't be described as "self-driving." Instead, it's properly referred to as an advanced driver-assist system (ADAS).
That may sound like splitting hairs, but it's a big deal because the expectations around a given system can affect how safe it is in practice. A Tesla Model S equipped with an early version of Autopilot was involved in a fatal accident in May 2016 when the car's system failed to recognize a tractor-trailer crossing the road -- and the human driver apparently didn't intervene to hit the brakes.
That was the first known fatal accident involving anything close to a self-driving system, and it emphasized that these systems needed to do a better job of ensuring that human drivers were alert and ready to take control on short notice.
That in turn led to considerable discussion within the industry: How could a system ensure that a human driver was alert without excessively annoying the human?
The challenge: How to keep the driver alert, but not annoyed?
Annoyance may seem like a trivial consideration when we're talking about avoiding fatal accidents. But consider this: If the system is too annoying to use, it won't get used.
The current version of Tesla's Autopilot warns drivers not to take their hands off of the steering wheel while the system is in use. To enforce that, the system has sensors that aim to detect whether the driver's hands are on the wheel.
If the driver's hands aren't on the wheel, the system gives a visual reminder after 30 seconds, followed by an audible warning after 45 seconds. After a minute with no intervention by the driver, the Autopilot system shuts off and can't be turned back on until the car is restarted.
It's not a bad system, but review have suggested that it's easy to fool -- drivers can just nudge the wheel when the lights come on to reset the warning cycle, while otherwise driving hands-free.
GM's Super Cruise incorporates an elegant solution
GM's solution allows for hands-free driving. Instead of detecting steering-wheel motions, it uses a camera to track the driver's head position. If the system detects that the driver's eyes aren't on the road, it begins a series of prompts to try to get the driver's attention back on the road.
Similar to Tesla's alerts, Super Cruise's prompts progress from a flashing light in the steering wheel's rim, to a beeping sound and seat vibrations, to a voice command -- at which point the Super Cruise system disengages. But GM goes further than Tesla: If the driver still doesn't take control at that point, the system will gradually bring the vehicle to a complete stop, activate the hazard warning flashers, and call for help (using GM's OnStar system.)
GM also built a slew of additional safeguards into Super Cruise to try to ensure that it's only used in circumstances it can safely handle. For starters, if the vehicle isn't on a highway, the road's lane markings aren't clearly visible, or the system thinks that the driver isn't fully attentive -- it won't even switch on. That may sound like a recipe for constant annoyance, but it's all elegantly implemented.
Most reviewers have agreed that Super Cruise is a pleasure to use.
The thing to remember: "Hands-free" isn't necessarily self-driving.
To sum up, a Level 2 system is an advanced driver-assist system that can allow for hands-free driving under limited circumstances. But the human driver has to remain alert and ready to take over the "dynamic driving task" on short notice, and the leading systems attempt to ensure that the driver remains alert while the systems are in use.
The SAE defines Level 3 as "conditional automation." The difference between Level 2 and Level 3 is a matter of degree. In practice, it depends on the answer to this question: How alert does the human in the vehicle's driver's seat have to be?
With a Level 2 system, the driver needs to be very alert, ready to take over the driving task right away right away if the system encounters something it can't handle. With Level 3, the expectation is that the system can handle the driving as long as it's within its "operational design domain," meaning that the human's role is to be a "fallback."
Here's how the SAE puts it:
The sustained and [operational design domain]-specific performance by an [automated driving system] of the entire [dynamic driving task] with the expectation that the [dynamic driving task] fallback-ready user is receptive to [automated driving system]-issued requests to intervene, as well as to [dynamic driving task] performance-relevant system failures in other vehicle systems, and will respond appropriately.
Got that?
If you're thinking that it's only a vague difference from Level 2, you're not alone.
Why many automakers are steering clear of Level 3?
The difficulty in defining (and explaining) a difference between Level 2 and Level 3 is the problem with Level 3 in practice. It's easy for us to understand that a Level 2 system isn't true self-driving, while (as we'll see below) Level 4 is self-driving, and it's fairly easy to explain that difference to users. But Level 3 seems to exist in between.
It's self-driving, except when it isn't.
That presents a challenge for engineers charged with developing a system. In a presentation in 2016, Ford Motor Company's (NYSE: F) former global product chief, Raj Nair, explained why Ford's road map for self-driving technology skips Level 3 entirely:
We found we couldn't safely get through scenarios that really concerned us without adding technology like LiDAR and like high-definition 3D maps. Once you go to that point, you're really at the solution for Level 4.
So we changed our direction from walking up driver assist technologies, the camera-based and radar-based technologies increasing at percentage, et cetera, to all the way leapfrogging into what does it take to get to Level 4, what does it take to get rid of the driver, what does it take to get rid of the steering wheel, the pedals, and then working on that technology problem.
Put simply: Once Ford engineers had added all of the technology needed to make their prototype Level 3 system meet their safety standards, they were essentially at Level 4. Given that, they reasoned, why plan to offer Level 3 at all?
But a few Level 3 systems are headed to market.
A lot of other automakers have reached the same conclusion about Level 3, but not all. There's another point of view, namely that Level 3 could be interpreted as a nicer implementation of the concepts behind Level 2 systems like Super Cruise.
That's Audi's view. Audi will launch a Level 3 system it calls "Traffic Jam Pilot" on its 2019 A8 sedan. Audi's pitch for the system effectively captures what it sees as the distinction between Level 2 and Level 3:
With Traffic Jam Pilot engaged, drivers no longer need to continuously monitor the vehicle and the road. They must merely stay alert and capable of taking over the task of driving when the system prompts them to do so.
But note: While Audi will offer this system in Germany, which recently passed laws making this type of system explicitly legal, Audi won't bring it to the United States -- at least, not yet -- because of concerns about liability and regulatory exposure.
It's not hard to see why. Even in Audi's own words, the distinction is still vague. The idea seems to be that Audi's system will give the human a bit more time to take over than a Level 2 system would.
But still: Does the human in the driver's seat need to be paying attention, or not?
Fortunately, the next level doesn't require such hair-splitting to understand.
The SAE says that Level 4 is "high driving automation": The system doesn't need a human backup at all, as long as it's operating within its "operational design domain." Put another way, a Level 4 system still has limits, but as long as it's within those limits, no human intervention will be needed -- it's real self-driving.
Here's what that means in practice.
Most of the "self-driving" systems under development today depend on highly detailed 3-D maps to help the vehicle's "brain" know exactly where it's located, down to a few centimeters (or less). These systems generally use several lidar units to "map" the vehicle's surroundings from moment to moment. The lidar images are then compared to a stored 3D map.
Some of the systems under development use the lidar-and-maps method as a primary method of locating the vehicle, while others use it as a backup. (One of the principles of full self-driving systems, like autopilot systems in aviation, is that all critical subsystems should have backups in case something fails.)
A Level 4 system is true self-driving as long as the system is operating within its limits. It doesn't matter whether the human sitting in the driver's seat is distracted, asleep, or not even present -- a Level 4 system will get the vehicle safely to its destination, as long as it's operating within its intended limits.
General Motors' first Level 4 vehicle, set to enter production in 2019, doesn't have a steering wheel or pedals. They're not needed as long as the vehicle operates within specified limits.
True Level 4 vehicles are beginning to arrive.
Level 4 vehicles are coming soon -- in fact, they're already here. Waymo, the Alphabet (NASDAQ: GOOGL) (NASDAQ: GOOG) subsidiary formerly known as the Google Self-Driving Car Project, began deploying Level 4 vehicles in a pilot ride-hailing service in Chandler, Arizona, earlier this year (2018).
General Motors (NYSE: GM) has said that its own self-driving subsidiary, GM Cruise, expects to deploy a fleet of "thousands" of Level 4 taxis in dense urban environments in the U.S. starting in 2019. Others will follow over the next few years.
But note that Waymo and GM aren't choosing locations at random. Waymo spent months "training" its prototype vehicles on the roads and traffic conditions in and around the Chandler area; GM Cruise has been doing the same with its Chevrolet Bolt-based vehicles in San Francisco.
For now, those vehicles are limited to the areas with which their systems are most familiar, all of which have been very carefully mapped.
Those limits are what make the systems Level 4. For instance, no matter how the maps are used, if the vehicle is dependent on a map, that means it's limited, because it can't go anywhere that isn't yet mapped. Of course, a Level 4 system could have other limits; it may not switch on if it detects heavy snow, for instance.
Long story short: If a system offers full automated driving within limits, the limits are what makes it Level 4.
Level 5 is the dream: Unconditional (that is, no-limits) automated driving, with no expectation that a human driver will ever have to intervene.
Put another way, a Level 5 system should be able to go anywhere a skilled human driver could go, under any conditions a skilled human driver could handle, entirely on its own.
Needless to say, there aren't any Level 5 systems available now. A few automakers, including Tesla and BMW, have claimed that they will have Level 5 systems within a few years -- but many experts believe that true Level 5 autonomy will take years to develop, if it ever happens at all.
It's possible that Level 5 systems will be the eventual result after lots of connected Level 4 vehicles are deployed and learning. Remember what I said about machine learning and fleet learning above?
Systems that are deployed in thousands of vehicles operating every day will amass huge amounts of data and encounter lots of new situations -- both of which mean they'll advance quickly on their own. Between this ongoing fleet learning and the expansion of well-mapped areas, the most widely deployed systems will effectively become Level 5 -- eventually.
Maybe.
It's also possible that a true Level 5 system -- a single system that can safely drive in a Montana snowstorm, a Shanghai traffic jam, and anywhere else a skilled human driver might be able to go -- won't come into being for many, many years (notwithstanding the bold promises made by certain CEOs).
Why full self-driving might still be years away?
Full self-driving is an incredibly difficult problem to solve. Consider that even Waymo -- which began way back in 2009 as the Google Self-Driving Car Project and has some of the best and most experienced engineers in the field -- is still having trouble getting its vehicles to safely navigate some routine traffic situations in suburban Chandler, where the situations are all known and the area is carefully mapped.
How do you think they'd fare in a completely unfamiliar environment -- downtown Mumbai, for instance?
A capable human driver from suburban Arizona would probably be able to navigate Mumbai pretty well with a smartphone and a bit of familiarization.
But at least right now in 2018, it looks like it could be many years before a self-driving system will be able to do the same -- and that means that true "full self-driving" won't arrive anytime soon.
However, in the long run it will happen as enginuity gets more advanced and sophisticated.
There you have it!
A beginner's guide to autonomous self-driving vehicle!





Now that you know how neurons work, let's see how to handle inputs and outputs so that we can do a weighted sum. How do we handle inputs and outputs?
Answer: use arrays to store inputs, outputs, and as well as weights [and biases]. For example, if we have three inputs as the diagram shown earlier, and now shown again below, which looks like this: x1, x2, x3, we put a '3' in the array like this: [3].
That '3' represents three input neurons: x1, x2, x3.
Here is the diagram that was shown earlier, and now shown here again below:

What about the hidden layers?
Well, we have two hidden layers with four neurons each, so we'll just put those numbers of neurons in the array like this: [3, 4, 4].
Now if we have more hidden layers, we can just put the numbers in the array seperating each hidden layer inputs with a comma "," as we did with the above example. Self-explanatory!!!
What about the output layers?
Well, it depends on what output layers we're talking about. If we're talking about the outputs from the hidden layers, we use the same array as shown above; and if we're talking about the final output layer, then we need another array to store the output for the final output layer.
The complete array example for the diagram shown above should look like this: [3, 4, 4, 1].
Remember that output neurons from one layer act as input neurons for the next layer.
As you can see the array contains three input neurons, four input/output neurons for the first hidden layer, four input/output neurons for the second hidden layer; and finally, one output neuron for the final output layer.
Let's see code example:
<?php
/**
* The array is passed in a constructor of the neural network class, for example:
*
* $net = new NeuralNetwork([3, 4, 4, 1]);
*
* More on classes NeuralNetwork and Layer later
*/
// Inside the constructor of class NeuralNetwork, we can do this:
// with $constructor_array_param containing [3, 4, 4, 1]
$this->input[0] = $constructor_array_param[0]; // 3
$this->input[1] = $constructor_array_param[1]; // 4
$this->input[2] = $constructor_array_param[2]; // 4
$this->input[3] = $constructor_array_param[3]; // 1
// this is how we can create hidden layers inside class NeuralNetwork's constructor:
// remember that output neurons from one layer act as input neurons for the next layer
// this is the input layer with three input neurons and four output neurons
$hidden_layer[0] = new Layer($this->input[0], $this->input[1]); // Layer(3, 4)
// this is the first hidden layer with four input/output neurons
$hidden_layer[1] = new Layer($this->input[1], $this->input[2]); // Layer(4, 4)
// if we have more hidden layers we can just create more instances of class Layer
// and passing the appropriate input/output neurons to the constructor of class Layer
// this is the second hidden layer with four input neurons, and one final output neuron
$hidden_layer[2] = new Layer($this->input[2], $this->input[3]); // Layer(4, 1)
?>
More code examples later.
Perceptron
Let's see code example for the above diagram:
<?php
/**
* The array is passed in a constructor of the neural network class, for example:
*
* $net = new NeuralNetwork([6, 4, 3, 1]);
*
* More on classes NeuralNetwork and Layer later
*/
// Inside the constructor of class NeuralNetwork, we can do this:
// with $constructor_array_param containing [6, 4, 3, 1]
$this->input[0] = $constructor_array_param[0]; // 6
$this->input[1] = $constructor_array_param[1]; // 4
$this->input[2] = $constructor_array_param[2]; // 3
$this->input[3] = $constructor_array_param[3]; // 1
// this is how we can create hidden layers inside class NeuralNetwork's constructor:
// remember that output neurons from one layer act as input neurons for the next layer
// this is the input layer with six input neurons and four output neurons
$hidden_layer[0] = new Layer($this->input[0], $this->input[1]); // Layer(6, 4)
// this is the first hidden layer with four input and three output neurons
$hidden_layer[1] = new Layer($this->input[1], $this->input[2]); // Layer(4, 3)
// if we have more hidden layers we can just create more instances of class Layer
// and passing the appropriate input/output neurons to the constructor of class Layer
// this is the second hidden layer with three input neurons, and one final output neuron
$hidden_layer[2] = new Layer($this->input[2], $this->input[3]); // Layer(3, 1)
?>
More code examples later.





Let's see code example for the above diagram to include biases:
<?php
/**
* The array is passed in a constructor of the neural network class, for example:
*
* $net = new NeuralNetwork([3, 3, 1]);
*
* More on classes NeuralNetwork and Layer later
*/
// Inside the constructor of class NeuralNetwork, we can do this:
// with $constructor_array_param containing [3, 3, 1]
$this->input[0] = $constructor_array_param[0]; // 3
$this->input[1] = $constructor_array_param[1]; // 3
$this->input[2] = $constructor_array_param[2]; // 1
$this->bias[0] = $constructor_array_bias[0]; // 1
// this is how we can create hidden layers inside class NeuralNetwork's constructor:
// remember that output neurons from one layer act as input neurons for the next layer
// also, we can create the constructor of class Layer with three arguments to accomodate the biases
// for example, public function __construct($numberOfInput, $numberOfOuput, $bias[] = null)
// then we can create instances of class Layer with three parameters: $numberOfInput, $numberOfOuput, $bias[]
// this is the input layer with three input and three output neurons
// Layer(3, 3, 1) <--- notice the last argument '1' is the bias
$hidden_layer[0] = new Layer($this->input[0], $this->input[1], $this->bias[0]);
// this is the first and only hidden layer with 3 input neurons, and one final output neuron
// Layer(3, 1, 1) <--- notice the last argument '1' is the bias
$hidden_layer[1] = new Layer($this->input[1], $this->input[2], $this->bias[0]);
?>
More code examples later.

Let's see code example for the above insurance policy:
<?php
/**
* The array is passed in a constructor of the neural network class, for example:
*
* two inputs: male, female
* 5 neurons in first hidden layer: age group
* 5 neurons in second hidden layer: income group
* 6 neurons in third hidden layer: FICO score group
* 4 neurons in fourth hidden layer: driving record group
* 1 neurons in the final output layer
*
* $net = new NeuralNetwork([2, 5, 5, 6, 4, 1]);
*
* More on classes NeuralNetwork and Layer later
*/
// Inside the constructor of class NeuralNetwork, we can do this:
// with $constructor_array_param containing [2, 5, 5, 6, 4, 1]
$this->input[0] = $constructor_array_param[0]; // 2
$this->input[1] = $constructor_array_param[1]; // 5
$this->input[2] = $constructor_array_param[2]; // 5
$this->input[3] = $constructor_array_param[3]; // 6
$this->input[4] = $constructor_array_param[4]; // 4
$this->input[5] = $constructor_array_param[5]; // 1
// this is how we can create hidden layers inside class NeuralNetwork's constructor:
// remember that output neurons from one layer act as input neurons for the next layer
// also, we can create the constructor of class Layer with three arguments to accomodate the biases
// for example, public function __construct($numberOfInput, $numberOfOuput, $bias[] = null)
// then we can create instances of class Layer with three parameters: $numberOfInput, $numberOfOuput, $bias[]
// this is the input layer with two input and five output neurons
// Layer(2, 5, 1) <--- notice the last argument '1' is the bias
// $hidden_layer[0] = new Layer($this->input[0], $this->input[1], $this->bias[0]);
// this is the input layer with two input and five output neurons
$hidden_layer[0] = new Layer($this->input[0], $this->input[1]); // Layer(2, 5)
// this is the first hidden layer with five input/output neurons
$hidden_layer[1] = new Layer($this->input[1], $this->input[2]); // Layer(5, 5)
// this is the second hidden layer with five input and six output neurons
$hidden_layer[2] = new Layer($this->input[2], $this->input[3]); // Layer(5, 6)
// this is the third hidden layer with six input and four output neurons
$hidden_layer[3] = new Layer($this->input[3], $this->input[4]); // Layer(6, 4)
// if we have more hidden layers we can just create more instances of class Layer
// and passing the appropriate input/output neurons to the constructor of class Layer
// this is the fourth hidden layer with four input neurons, and one final output neuron
$hidden_layer[4] = new Layer($this->input[4], $this->input[5]); // Layer(4, 1)
?>
More code examples later.
There you have it! Have a go at it!
<?php
/**
* file: neuralnetwork.php
*
* Simple MLP (Multi-layers Perceptron) Neural Network
*/
class NeuralNetwork
{
private $input = array(); // input information which contains the # of input items
private $hidden_layer = array(); // holds the # of layers in the network
/**
* Constructor setting up layers
* A calling program needs to create an instance of this class and passing
* input layer, hidden layers, and output layer.
*
* Usage:
*
* $net = new NeuralNetwork([3, 25, 25, 1 ]);
*
* After that, we need to call FeedForward() and BackPropagation().
* in this example, we pass the known value of XOR function as an array:
*
* $net.FeedForward([ 0, 0, 0 ]);
* $net.BackPropagation([ 0 ]);
*
* we can train some more:
*
* $net.FeedForward([ 0, 0, 1 ]);
* $net.BackPropagation([ 1 ]);
*
* $net.FeedForward([ 0, 1, 0 ]);
* $net.BackPropagation([ 1 ]);
*
* $net.FeedForward([ 0, 1, 1 ]);
* $net.BackPropagation([ 0 ]);
*
* $net.FeedForward([ 1, 0, 0 ]);
* $net.BackPropagation([ 1 ]);
*
* $net.FeedForward([ 1, 0, 1 ]);
* $net.BackPropagation([ 0 ]);
*
* $net.FeedForward([ 1, 1, 0 ]);
* $net.BackPropagation([ 0 ]);
*
* $net.FeedForward([ 1, 1, 1 ]);
* $net.BackPropagation([ 1 ]);
*
* @param $input Layers of this network
*/
// notice the type-hint which indicates $input is an array variable
// example usage: $net = new NeuralNetwork([3, 25, 25, 1 ]);
// or: $net = new NeuralNetwork([784, 25, 25, 1 ]); // 784 inputs? (28 pixels * 28 pixels)
public __construct(array $input)
{
// initialize input layers that were passed in by the calling program
for ($i = 0; $i < sizeof($input); $i++)
{
// $input argument contains: 3 inputs, 25 neurons in hidden layer 1,
// 25 neurons in hidden layer 2, 1 output
// store each argument in this class' array variable $input
$this->input[$i] = $input[$i];
}
/*
the for() loop above result in the following initialization:
$this->input[0] = 3;
$this->input[1] = 25;
$this->input[2] = 25;
$this->input[3] = 1;
*/
// creates a bunch of neural network hidden layers,
for ($i = 0; $i < count($input) - 1; $i++)
{
// for each argument in [count($input)], create a Layer object passing
// this class' array variable $input
// in other words, create one Layer object for the input layer (index 0),
// one for the first hidden layer (index 1),
// one for the 2nd hidden layer (index 2),
// leaving the output (index 3) uneffected.
// follow the for() loop iteration to make sense of all this statement:
$this->hidden_layer[$i] = new Layer($this->input[$i], $this->input[$i + 1]);
}
/*
the for() loop above result in the following initialization:
// input = 3, hidden layer = 25 => (3, 25)
$this->hidden_layer[0] = new Layer($this->input[0], $this->input[0 + 1]);
// hiddenl = 25, hiddenl = 25 => (25, 25)
$this->hidden_layer[1] = new Layer($this->input[1], $this->input[1 + 1]);
// hiddenl = 25, hidden layer = 25 => (25, 1)
$this->hidden_layer[2] = new Layer($this->input[2], $this->input[2 + 1]);
// so this last index is not iterated because of count($input) - 1, which is
// when $i = 3. 3 < 3 is false,
// so this last line is not executed at last iteration
// hidden l = 25, hidden layer 2 = 25 => (1, null)
// again, follow the for() loop iteration to make sense of all this statement:
$this->hidden_layer[3] = new Layer($this->input[3], $this->input[3 + 1]);
*/
}
/**
* A feedforward for this network
* this function is called by the training application to kickstart the process:
*
* // notice the argument is passed in as an array and the array
* can contain limitless size. here, we pass in five layers.
* notice that we have two hidden layers 25 neurons each.
* if we have more hidden layers we can pass in more arguments seperate each
* argument with a comma, e.g.: 784 (inputs),
* (five hidden layers:) 25, 25, 8, 4, 17, (and one output:) 1
*
* for example:
* new NeuralNetwork([784, 25, 25, 8, 4, 17, 1 ])
*
* Now back to our original example:
*
* Usage:
*
* $net = new NeuralNetwork([3, 25, 25, 1 ]);
*
* calling FeedForward() passing the known answer. in this example, we're
* calling FeedForward() and passing the known value as an array.
* you can pass in your actual number sets to train, but in this case, we just
* pass in an XOR function values (analogous to an "Hellow World" example): 0, 0, 0
*
* $net.FeedForward([ 0, 0, 0 ]);
*
* so all applications need to call this so called "train" function to start the process.
* some programmers like to name this function as "train()" but I like "FeedForward()"
*
* @param $input # of inputs to be feed forward
*/
// this function acts as a train() function to train or jumpstart the process
public FeedForward($input)
{
// feed forward. notice the call to FeedForward -- it's not a recursive call, but
// rather, it is actually calling Layer's FeedForward($input) because
// $this->hidden_layer[0] refers to Layer's object
$this->hidden_layer[0]->FeedForward($input);
// so after the above call to FeedForward($input),
// Layer's $output should contains a weighted sum of the input
for ($i = 1; $i < count($this->hidden_layer); $i++)
{
// start with the 2nd Layer object instance (index 1) and call
// Layer's FeedForward() passing the output of layer 0
$this->hidden_layer[$i]->FeedForward($this->hidden_layer[$i - 1]->output);
}
// return the output of the last layer
return $this->hidden_layer[$i - 1]->output; // $i = 3
}
/**
* High level back propagation
* Note: It is expected the one feed forward was done before this back prop.
* @param $expected The expected output form the last feedforward
*/
// notice that $expected is the known answer passed in by calling code
public BackPropagation($expected)
{
// run over all layers backwards. notice that the for() loop starts from
// the total number of hidden layers and iterated downward to 0
for ($i = sizeof($this->hidden_layer) - 1; $i >= 0; $i--)
{
if ($i == sizeof($this->hidden_layer) - 1)
{
// doing a backward propagation output
$this->hidden_layer[$i]->BackPropagationOutput($expected);
}
else
{
//back prop hidden
$this->hidden_layer[$i]->BackPropagationHidden($this->hidden_layer[$i +
1]->gamma,
$this->hidden_layer[$i + 1]->weight);
}
}
//Update weights
for ($i = 0; $i < sizeof($this->hidden_layer); $i++)
{
$this->hidden_layer[$i]->UpdateWeight();
}
} // end BackProp($expected)
} // end class NeuralNetwork
/**
* Each individual layer in a ML (Multi-Layer) perceptron
*/
class Layer
{
public $numberOfInput; // # of neurons in the previous layer
public $numberOfOuput; // # of neurons in the current layer
public $output = array(); // outputs of this layer
public $input_layer = array(); // inputs in into this layer
public $weight[][]; // weights of this layer, a two-dimensional array
public $weightDelta[][]; // deltas of this layer, a two-dimensional array
public $gamma = array(); // gamma of this layer
public $error = array(); // error of the output layer
public static $random = new rand(); // Static random class variable
/**
* Constructor initilizes various data structures
*
* @param $numberOfInput Number of neurons in the previous layer
* @param $numberOfOuput Number of neurons in the current layer
*
* note that $this->input refers to NeuralNetwork's member array variable $input
* // input = 3, hidden layer = 25 => (3, 25)
* $this->hidden_layer[0] = new Layer($this->input[0], $this->input[0 + 1]);
* // hiddenl = 25, hiddenl = 25 => (25, 25)
* $this->hidden_layer[1] = new Layer($this->input[1], $this->input[1 + 1]);
* // hidden l = 25, hidden layer 2 = 25 => (25, 1)
* $this->hidden_layer[2] = new Layer($this->input[2], $this->input[2 + 1]);
* // so this last index is not iterated because of count($input) - 1, which is
* // when $i = 3. 3 < 3 is false
* // hiddenl = 25, hidden layer = 25 => (1, null)
* $this->hidden_layer[3] = new Layer($this->input[3], $this->input[3 + 1]);
*
* we're not implementing biases as of right now, but we can further down the road!
*/
public __construct($numberOfInput, $numberOfOuput, $bias[] = null)
{
$this.numberOfInput = $numberOfInput; // 3 neurons from the previous layer
$this.numberOfOuput = $numberOfOuput; // 25 neurons in the current layer
//initialize data structures
// these need to be refined and probably involve matrix manipulation
// or we can use for loops to initialize the matrix:
for ($i = 0; $i < $this->numberOfOuput; $i++)
{
for ($j = 0; $j < $this->numberOfInput; $j++)
{
// need to refine these
$this->weight[$i][$j] = 0;
$this->weightDelta[$i][$j] = 0;
}
}
// all it does above is initializing the array elements to their default values.
// all the array elements are initialized to zero.
$this->InitilizeWeight(); //initilize weights
}
/**
* Initilize weights randomly between -0.5 and 0.5
*/
public InitilizeWeight()
{
for ($i = 0; $i < $this->numberOfOuput; $i++)
{
for ($j = 0; $j < $this->numberOfInput; $j++)
{
// you need to refine the following statment to suite your purpose!
// basically it needs to initialize the weight for each input so that
// it can be used to do a weighted sum for all inputs
// remember that each input is multiplied with its weight to make it a
// weighted input, and then sum all of the weighted inputs.
// the following line attempts to assign a weight to each input so that
// it can be used to do a weighted input and then they can be used to
// sum for all inputs: hence, weighted sum!
// you can probably do a better job by querying from a database that stores
// all the weights for each input, and then assign each weight to this statement!
// here, I just used a random weight from -0.5 to 0.5 for demonstration purpose only!
$this->weight[$i][$j] = rand(-0.5, 0.5);
}
}
}
/**
* Feedforward this layer with a given input
*
* @param $input The output values of the previous layer
*/
public FeedForward($input)
{
// initialize the layers which can be used for backward propagation
$this->input_layer = $input;
// feed forward
for ($i = 0; $i < $this->numberOfOuput; $i++)
{
$this->output[$i] = 0;
for ($j = 0; $j < $this->numberOfInput; $j++)
{
// this is the output sum of the activation function: sigmoid, tanH,...
// this is where we can add a bias to the output sum
// $this->input_layer[$j] * $this->weight[$i][$j] + $this->bias[$j]
$this->output[$i] += $this->input_layer[$j] * $this->weight[$i][$j];
}
// I need to refine and maybe use sigmoid() instead
// $this->output[$i] = (float)Math.Tanh($this->output[$i]);
$this->output[$i] = call_user_func_array(array('sigmoid', $this->output[$i]);
}
// in the calling code, it only returns output of the last layer even though (below)
// we return the full array of output result. see FeedForward($input) earlier,
// which returns $this->hidden_layer[$i - 1]->output; // $i = 3
return $this->output;
}
/**
* Activation functions.
*
* You can use other activation functions as well: sigmoid(), ReLU(), softmax, etc.
* Here are a few examples:
*
* public function sigmoid($x)
* {
* return 1 / (1 + pow(M_E, -$x));
* }
*
* here is a derivative of sigmoid() above:
*
* public function dsigmoid($y)
* {
* // return sigmoid($x) * (1 - sigmoid($x));
* return $y * (1 - $y);
* }
*
* ReLU
*
* public function relu($x)
* {
* //$x = $x > 0 ? 1 : 0;
* return $x > 0 ? 1 : 0;
* }
*
* TanH:
*
* public function getTanH($x)
* {
* // return the computed tanH()
* return tanh($x);
* }
*
* Or use it directly:
*
* echo tanh(M_PI_4); // output: 0.65579420263267
* echo tanh(0.50); // output: 0.46211715726001
* echo tanh(-0.50); // output: -0.46211715726001
* echo tanh(5); // output: 0.9999092042626
* echo tanh(-5); // output: -0.9999092042626
* echo tanh(10); // output: 0.99999999587769
* echo tanh(-10); // output: -0.99999999587769
*/
/**
* TanH derivative - a derivative function for TanH
*
* @param $value An already computed TanH value, for example: 0.65579420263267
*
* Notice that to use this TanHDer() you first have to get the value of tanh() and
* then call this function passing the computed value to it. See example above.
*/
public TanHDer($value)
{
return 1 - ($value * $value);
}
/**
* Back propagation for the output layer
*
* @param $expected The expected output
*/
public BackPropagationOutput($expected)
{
// Error derivative of the cost function
for ($i = 0; $i < $this->numberOfOuput; $i++)
{
$this->error[$i] = $this->output[$i] - $expected[$i];
}
// Gamma calculation
for ($i = 0; $i < $this->numberOfOuput; $i++)
{
$this->gamma[$i] = $this->error[$i] * $this->TanHDer($this->output[$i]);
}
// Caluclating delta weights
for ($i = 0; $i < $this->numberOfOuput; $i++)
{
for ($j = 0; $j < $this->numberOfInput; $j++)
{
$this->weightDelta[$i, $j] = $this->gamma[$i] * $this->input_layer[$j];
}
}
}
/**
* Back propagation for the hidden layers
*
* @param $gammaForward the gamma value of the forward layer
* @param $weightFoward the weights of the forward layer
*/
public BackPropagationHidden($gammaForward, $weightFoward[][])
{
// Caluclate new gamma using gamma sums of the forward layer
for ($i = 0; $i < $this->numberOfOuput; $i++)
{
$this->gamma[$i] = 0;
for ($j = 0; $j < count($gammaForward); $j++)
{
$this->gamma[$i] += $gammaForward[$j] * $weightFoward[$j, $i];
}
$this->gamma[$i] *= $this->TanHDer($this->output[$i]);
}
// Caluclating detla weights
for ($i = 0; $i < $this->numberOfOuput; $i++)
{
for ($j = 0; $j < $this->numberOfInput; $j++)
{
$this->weightDelta[$i, $j] = $this->gamma[$i] * $this->input_layer[$j];
}
}
}
/**
* Updating weights
*/
public UpdateWeight()
{
for ($i = 0; $i < $this->numberOfOuput; $i++)
{
for ($j = 0; $j < $this->numberOfInput; $j++)
{
// learning rate is hardcoded to 0.033
$this->weight[$i, $j] -= $this->weightDelta[$i, $j] * 0.033f;
}
}
}
} // end class Layer
?>
<?php
/*
* file: block.php
*
* a complete blockchain implementation will still need a P2P network
* so we need to implement a P2P network.
*/
class Block
{
public __constructor($index, $timestamp, $transaction, $previousHash = '')
{
$this->index = $index;
$this->previousHash = $previousHash;
$this->timestamp = $timestamp;
//$this->data = $data;
$this->transaction = $transaction;
$this->hash = $this->calculateHash();
$this->nonce = 0;
}
public function calculateHash()
{
// return hash('SHA256', strval($this->previousHash .
// $this->timestamp . json_encode($this->transaction) . $this->nonce));
return hash('SHA256', $this->previousHash .
$this->timestamp . ((string)$this->transaction) . $this->nonce);
}
// Implementing Proof-of-Work
public function mineBlock($difficulty)
{
// takes the array elements, converts to string and concatenates 0 to it
while (substr($this->hash, 0, $difficulty) !== str_repeat("0", $difficulty))
{
$this->nonce++;
$this->hash = $this->calculateHash();
}
//echo("BLOCK MINED: " + $this->hash);
}
} // end class Block
<?php
/*
* file: blockchain.php
*
* a complete blockchain implementation will still need a P2P network
* so we need to implement a P2P network.
*/
/**
* usage:
*
* $coin = new Blockchain();
* $coin->createTransaction(new Transaction('address1', 'address2', 100));
* $coin->createTransaction(new Transaction('address2', 'address1', 50));
*
* echo('\n Start mining...');
* $coin->minePendingTransaction('john-doe-address');
*
* echo('\nBalance of John Doe is') . $coin->getBalanceOfAddress('john-doe-address');
*
* echo('\n Start mining again...');
* $coin->minePendingTransaction('john-doe-address');
*
* echo('\nBalance of John Doe is') . $coin->getBalanceOfAddress('john-doe-address');
*/
class Blockchain
{
public $chain = array();
public __constructor()
{
// this chain should hold an array of object of genesis block
// should be without the "[]"
// need to refine.
// $chain holds an array of Block objects ... lots of it.
// this is where we hold blocks of transaction.
$this->chain = [$this->createGenesisBlock()]; // need to refine this
$this->difficulty = 2;
// this array propery is assigned transactions by minePendingTransaction() below
$this->pendingTransaction = array();
$this->miningReward = 100;
}
public function createGenesisBlock()
{
// the return statement just returns an instance of Block.
// so the constructor that calls this function assigns an instance of Block and
// that is it!
// need to refine this call: notice that only three arguments are passed in!
// this is because the fourth argument is optional: $previousHash = ''
// need to refine these calls!
//return new Block(0, strtotime("2017-01-01"), "Genesis Block");
return new Block(new DateTime('2000-01-01'), [], "0"); // [] short cut array
}
public function getLatestBlock()
{
// count the # of array elements in the chain by subtracting 1 to get the
// last element in the array and therefore getting the last block.
// array element starts at 0, 2nd element is 1, 3rd element is 2, etc.
return $this->chain[count($this->chain) - 1];
}
public function minePendingTransaction($miningRewardAddress)
{
// $this->getLatestBlock()->hash refers to the chain's property hash which
// holds the block's hash strings
$block = new Block(new DateTime(), $this->pendingTransaction,
$this->getLatestBlock()->hash;
$block->mineBlock($this->difficulty);
echo ('Block successfully mined!');
// push the chain onto the block to be stored in the blockchain serial
array_push($this->chain, $block);
// storing the transactions in this class's
// array property $this->pendingTransaction
$this->pendingTransaction = [
new Transaction(null, $miningRewardAddress,
$this->miningReward)
];
}
// create a transaction passing an instance of the Transaction object containing
// $fromAddress, $toAddress, $amount
// and then push this transaction object onto the array list: pendingTransaction
// createTransaction() receives a 'new Transaction("address1", "address2", 100)'
// instance object as its argument
public function createTransaction($transaction)
{
// storing the transactions in this class's
// array property $this->pendingTransaction
array_push($this->pendingTransaction, $transaction);
}
public function getBalanceOfAddress($address)
{
$balance = 0;
foreach ($this->chain as $block)
{
foreach ($block->transaction as $trans)
{
if ($trans->fromAddress === $address)
{
$balance -= $trans->amount;
}
if ($trans->toAddress === $address)
{
$balance += $trans->amount;
}
}
}
return $balance;
}
public function isChainValid()
{
for ($i = 1; $i < count($this->chain) + 1; $i++)
{
$currentBlock = $this->chain[$i];
$previousBlock = $this->chain[$i - 1];
if ($currentBlock->hash !== $currentBlock->calculateHash())
{
return false;
}
if ($currentBlock->previousHash !== $previousBlock->hash)
{
return false;
}
}
return true;
}
} // end class Blockchain
<?php
/*
* file: transaction.php
*
* a complete blockchain implementation will still need a P2P network
* so we need to implement a P2P network.
*/
class Transaction
{
public __constructor($fromAddress, $toAddress, $amount)
{
$this->fromAddress = $fromAddress;
$this->toAddress = $toAddress;
$this->amount = $amount;
}
} // end class Transaction
Here are some of the video tutorials that you can get started learning peer-to-peer network:
Peer to Peer Network: P2P Network - Fundamental Concepts Peer to Peer Network: What is a peer to peer system? Peer-to-peer (P2P) Networks - Basic Algorithms Peer-to-peer (P2P) Networks: Routing in Distributed Hash Tables Peer-to-peer (P2P) Networks: Hash Tables Introduction to Decentralized P2P Apps Peer to Peer: MIT 6.824 Distributed Systems (Spring 2020) Peer to Peer: What is a distributed system?
Very surprisingly, to say the least, there aren't many open-source PHP peer-to-peer network libraries out there on the Internet. So now the choices are to write your peer-to-peer network applications in other languages, say, Javascript, Node.JS, or even in a language called Go! (a not very well-known language but it is very suitable for writing peer-to-peer network applications.) This language (Go!) is built specifically for programming peer-to-peer network applications.
Anyhow, here are some libraries:
Peer to Peer Network Libraries in PHP
Peer to Peer Network Libraries in Go!
Peer to Peer Network Examples in Go!
Peer to Peer Network Tutorials 'README' File in Go!
As you might have already knew that PHP is not a language that is suitable for programming blockchain applications. However, Javascript is very much suitable for programming blockchain applications since it does have multithread capabilities, whereas PHP does not.
So if you are familiar with the language of Javascript, particularly Node.JS, you can use Javascript to program your blockchain applications. Here is a library for building blockchain applications using Javascript, particularly using Node.JS, which uses a native Javascript language.
Lisk: the blockchain application platform
There you have it! A blockchain application platform for building blockchain applications.
Article Date: October 20, 2013
By Paul S. Tuon
Update: As of October 1, 2020, the old PHP's MySQL api has been deprecated. Thank god!!!.
So use PDO instead.
File name incuding directory: Home/Database/connection.php
<?php
// arbitrarily name you give it when
// you create during phpMyAdmin setup
$databaseName = "db1.abc.10077";
//given to you by your hosting co.
$hostingserver = "db1.abc10077.example.com";
// either given to you or you create it yourself
$username = "yourUsername";
// either given to you or you create it yourself
$password = "yourPassword";
?>
<?php
include('Home/Database/connection.php');
$conn = new PDO("mysql:host=$hostingserver;dbname=$databaseName",
$username, $password,
array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8'));
?>
As you can see, to connect to MySQL, you need to create an instance of the PDO object and passing all the necessary parameters (up to maximum of four parameters) to it and assign that instance object to a variable name $conn.
The class PDO is already in the PHP standard library; and therefore, it is available for use in your PHP script just like any built-in PHP class. So you don't need to include it or import it from somewhere -- it is available everywhere in your PHP script.
The fourth parameter is the driver options that you can set as an array: such as charset as in the example above or ATTR_ERRMODE, ERRMODE_EXCEPTION, ATTR_EMULATE_PREPARES and a whole host of options which is too many to list here.
<?php
include('Home/Database/connection.php');
$conn = new PDO("mysql:host=$hostingserver;dbname=$databaseName;
port=your_database_port_number;charset=utf8",
$username, $password);
?>
<?php
include('Home/Database/connection.php');
try
{
$conn = new PDO("mysql:host=$hostingserver;dbname=$databaseName",
$username, $password);
$conn->setAttribute(PDO::ATTR_ERRMODE,
PDO::ERRMODE_EXCEPTION);
}
catch (PDOException $e)
{
echo 'Cannot connect to the database. ' . $e->getMessage();
}
?>
The Scope Resolution Operator "::" (the double colon) is a token that allows access to static, constant, and overridden properties or methods of a class. In other words, it is a static class operator used to refer to static constant, (static) properties, and (static) methods of a class.
In this case, it refers to a constants called ATTR_ERRMODE and ERRMODE_EXCEPTION. For on the Scope Resolution Operator "::", please see my other tutorial called $this verses Self verses Parent.
The 'catch' block takes a PDO exception class (PDOException) that returns an error in a variable that follows it -- and in this case -- $e. You can name this variable any name you wish. PDOException class also has a method called getMessage() that returns the error message it generates when it encounters any error in your query.
<?php
include('Home/Database/connection.php');
try
{
$conn = new PDO("mysql:host=$hostingserver;dbname=$databaseName",
$username, $password,
array(PDO::ATTR_PERSISTENT => true,
PDO::ATTR_ERRMODE => true,
PDO::ERRMODE_EXCEPTION => true));
}
catch (PDOException $Exception)
{
echo 'Connection error: ' . $Exception->getMessage();
}
?>
<?php
include('Home/Database/connection.php');
try
{
//initiate an instantiation
$conn = new PDO("mysql:host=$hostingserver;dbname=$databaseName",
$username, $password);
//after instantiation
$conn->setAttribute(PDO::ATTR_PERSISTENT, PDO::ATTR_ERRMODE,
PDO::ERRMODE_EXCEPTION));
}
catch (PDOException $ex)
{
echo 'Connection error: ' . $ex->getMessage();
}
?>
<?php
include('Home/Database/connection.php');
try
{
$conn = new PDO("mysql:host=$hostingserver;dbname=$databaseName",
$username, $password);
// use the connection here
// ....
}
catch (PDOException $exception)
{
echo 'Cannot connect to the database. '.$exception->getMessage();
}
// and now we're done; close it
$conn = null;
?>
I intentionally left out the detail of creating a database and table when we discussed the database connection and leave it for this discussion. Although creating a table is uniform for all databases, however, creating a database is not uniformed -- meaning different databses and admins have different methods of dealing with databases creation.
For example, you can use PhpMyAdmin tool to create databases and tables and pretty much you can do a lot of other things as well to make your life much easier. I recommend you make use of the PhpMyAdmin to do your database job on your everyday database programming chores.
If you have a localhost server installed on your computer PhpMyAdmin comes with the localhost program as well, and you can use it to do your database chores as well. For more tutorial on localhost, please see my other tutorial called "Get Started Programming for Beginners" and you'll find a section on that tutorial that deals with localhost.
Here is a look at the screenshots of the PhpMyAdmin that are partially shown due to space constraint:

Whenever you open your PhpMyAdmin tool a generic screen should look like the one shown above. Of course, the above screen is only partially shown due to space constraint.
On the left side it lists some database names that already been created. Here, I created some database names called dashboard, noon2noon, and noonshop. The rest are just database schemas created by PhpMyAdmin and no one should touch them at all.
As you can see, there is a menu called "New" as well for creating a new database. When you need to create a new table, you first need to create a database, and after that, you can then create a table. To create a database just click on the "New" menu button and a screen that looks like the following will open up for you to fill in the database name.
Pay speciall attention to the right side pane where there are several items that you can do -- like export/import your database tables to this PhpMyAdmin.

In the above screenshot, you can create a database by filling in your database name in the input box in place of "Database name" and once you're finished click the "Create" button to create the database. And it will create a database for you [similar to my databases dashboard, noon2noon, and noonshop and as well as 3149662_org below].
In the following screenshot, here is one of my database that I created called 3149662_org. In this database I created ten tables (see the left side pane).

Similarly as the previous screenshot, the above screenshots allows you to enter the table name along with the table fields. All of these are self-explanatory. So please make use of the PhpMyAdmin to do your database chores. It's a lot easier than the one shown in the following tutorial.
In the screenshots shown previously, you can create databases and tables easily using PhpMyAdmin tool. However, in the following tutorial, you can create databases manually by hands as well.
So here, we will discuss how to create a database and a table manually by hand programically using PHP script. So to insert data into the database, we need to have a database and a table ready. But first, let's create a database and a table called my_database and membership_table, respectively.
<?php
$db_name = 'my_database';
$host = 'htttp://www.myhostingserver.com';
$username = 'my_user123';
$password = 'my_pass123';
try
{
// now just connect to the PDO
$conn = new PDO("mysql:host = $host", $username, $password);
// now create the actual database called 'my_database'
$conn->exec("CREATE DATABASE `$db_name`;");
}
catch (PDOException $e)
{
die("DB ERROR: ". $e->getMessage());
}
// that's is it!!!
// you now have a database name called 'my_database' in your database server.
// Or you can get the same result as above without using a try ... catch block:
$db_name = 'my_database';
$host = 'htttp://www.myhostingserver.com';
$username = 'my_user123';
$password = 'my_pass123';
// now just connect to the PDO
$conn = new PDO("mysql:host = $host", $username, $password);
// now create the actual database called 'my_database'
$conn->exec("CREATE DATABASE `$db_name`;") or die(print_r($conn->errorInfo(), true));
// that's is it!!!
// you now have a database name called 'my_database' in your database server.
// go to your database hosting server or your PhpMyAdmin tool and check to see
// if a database called 'my_database' have been created! it should!!!
// once you have a database name in your database server, you can use it to
// create database tables and do everything else that you need to do!!!
?>
Now that a database already have been created, we can go ahead and create a table called membership_table.
<?php
//create a table named membership_table if it doesn't exist in the database name
try
{
$conn->query("CREATE TABLE IF NOT EXISTS `membership_table`
(
`id` int(10) NOT NULL auto_increment, // id is increment automatically
`name` varchar(25) NOT NULL,
`address` varchar(64),
`email` varchar(64) NOT NULL,
// just to have a variety for demonstrative purpose
`price` float(10,2), // can be null,10 digits with 2 decimal
`description` text(64), // also can be null
`date_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
// the following definitions are advanced uses for key manipulations
PRIMARY KEY (`id`), // used for referring to certain id
UNIQUE KEY `id` (`id`), // for referring to a unique id
// full text searching similar to Google search
FULLTEXT (`name`, `address`, `email`, `description`)
)
// MySQL 5.7 or higher: InnoDB is the default storage engine but
// consumes more bytes.
// So MyISAM is the preferred choice here/consuming less bytes and
// runs faster.
// Optional: DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
// Just put only: ENGINE=MyISAM");
// without the optional: DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci");
}
catch (PDOException $e)
{
echo "Error: Fail to create a table. " . $e->getMessage();
}
?>
/**
* Notice that the use of the DEFAULT clause to give the table columns an
* initial value so that the query operations can proceed without having
* to supply new values.
*
* For example, the table field column `date_time` looks like this:
*
* `date_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
*
* See an explanation later on the function CURRENT_TIMESTAMP
*
* The two most frequently used data types are VARCHAR and INT.
* But occasionally, you'll use TEXT instead of VARCHAR for description
* and CHAR for character a-z or A-Z and special characters!
*
* Other data types are:
*
* Numeric:
*
* TINYINT
* SMALLINT
* MEDIUMINT
* BIGINT
* INT
*
* DECIMAL
* DOUBLE
* FLOAT
* REAL
*
* these three are rarely used:
*
* BIT
* BOOLEAN
* SERIAL
*
* Date and time:
*
* DATE
* DATETIME <-- will output date and time: 2020-08-07 15:47:01
* TIMESTAMP <-- output date/time in timestamp: 509173028064019
* TIME
* YEAR
*
* String:
*
* CHAR
* VARCHAR
*
* TEXT
* TINYTEXT
* MEDIUMTEXT
* LONGTEXT
*
* BINARY
* VARBINARY
*
* BLOB
* TINYBLOB
* MEDIUMBLOB
* LONGBLOB
*
* these two are rarely used:
*
* ENUM
* SET
*/
<?php
// Let's prepare to insert Joe's data into membership database
$name = 'Joe Public1';
$email = 'abc@example.com';
$address = '123 Main St';
// hours in 24-hour military time
// displays: 04-26-2016 20:01:04
$current_date_time = date("m-d-Y H:i:s");
// displays: 26-04-2016 20:01:04
$current_date_time = date("d-m-Y H:i:s");
// displays: 2016-04-26 20:01:04
$current_date_time = date("Y-m-d H:i:s");
try
{
# Prepare to insert Joe's data into club's membership database
# using ??????
$stmt = $conn->prepare('INSERT INTO membership_table
(name, address, email, price, description, created_time)
VALUES(?, ?, ?, ?, ?, ?)');
// you should make a habbit to use array shortcut: [] instead!
// for example: $stmt->execute(['name' => $name,
// 'address' => $address,
// 'email' => $email,
// 'price' => $price,
// 'description' => $description,
// ....
// ]);
$result = $stmt->execute(array(
// you can omit the single quote on the
// right side as well. for example:
// 'name' => $name,
// $name will be converted into an array
// string, so single quote is not needed!
// 'name' => $name,
// 'name' => ' . $name . ', // not needed!
'name' => $name, // better!
'address' => $address,
// 'address' => ' . $address . ',
'email' => $email,
// 'email' => ' . $email . ',
'price' => $price,
// 'price' => ' . $price . ',
'description' => $description,
// 'description' => ' . $description . ',
'created_time' => $current_date_time
// 'created_time' => ' . $current_date_time . '
)
);
# For debugging purpose? Affected rows?
# output 1 row.
# rowCount() is similar to mysql_num_rows() for the old PHP API
echo "Data has been entered successfully: " . $result->rowCount();
}
catch (PDOException $e)
{
echo "Can't insert data into database. " . $e->getMessage();
}
?>
If you look in the create table definition, you'll notice that a table field called `date_time` uses a function called CURRENT_TIMESTAMP to automatically generate date and time every time an INSERT or an UPDATE operation is taking place.
So optionally, you don't need to insert (or update) the current date and time manually as shown in the examples throughout this tutorial. So instead of having to do an INSERT or an UPDATE operation using all six fields, you can just do an operation using only five fields. For example:
<?php
// Preparing data to insert into the database
$name = 'Joe Public1';
$email = 'abc@example.com';
$address = '123 Main St';
$price = '24.95';
$description = 'testing';
try
{
// notice the use of only five fields
$stmt = $conn->prepare('INSERT INTO membership_table
(name, address, email, price, description)
VALUES(?, ?, ?, ?, ?)');
// notice that you can use placeholder as well, example:
// VALUES(:name, :address, :email, :price, :description)');
// placeholder for execute():
// $result = $stmt->execute([':name' => $name,
// ':address' => $address,
// ':email' => $email,
// ':price' => $price,
// ':description' => $description
// ]
// );
// notice the use of only five fields: no `date_time`
// using array shortcut: []
$result = $stmt->execute(['name' => $name,
'address' => $address,
'email' => $email,
'price' => $price,
'description' => $description
]
);
echo "Data has been entered successfully: " . $$result->rowCount();
}
catch (PDOException $e)
{
echo "Can't insert data into database. " . $e->getMessage();
}
?>
/**
* As you can see above, there are only five fields and yet the
* create table definition contains 10 fields. But five of them
* are handled by MySQL automatically including the function
* CURRENT_TIMESTAMP.
*
* Now for the field that has a function CURRENT_TIMESTAMP,
* MySQL automatically generates a date and time for you and
* inserts it in the database every time you do an INSERT or
* an UPDATE operation.
*
* This saves us the need to manually insert the date and time.
*
* In the tutorial throughout, I opted to do it manually for
* educational purpose only.
*
* In your case, please let MySQL do it for you automatically!
*/
<?php
include('Home/Database/connection.php');
try
{
$conn = new PDO("mysql:host=$hostingserver;dbname=$dbname",
$username, $password);
// set the PDO error mode to exception
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch (PDOException $e)
{
echo 'ERROR: Can't connect to the database. ' . $e->getMessage();
}
try
{
// prepare sql and bind parameters
$stmt = $conn->prepare("INSERT INTO membership_table (name,
address, email, price, description, created_time)
VALUES (:name, :address, :email, :price, :description, :created_time)");
$stmt->bindParam(':name', $name);
$stmt->bindParam(':address', $address);
$stmt->bindParam(':email', $email);
$stmt->bindParam(':price', $price);
$stmt->bindParam(':description', $description);
$stmt->bindParam(':created_time', $created_time);
// insert a row of values
$name = "Joe Public";
$address = "123 main st";
$email = "joe@example.com";
$price = 10.00;
$description = "this is a description";
$created_time = date("Y-m-d H:i:s");
// now execute it to take effect
$result = $stmt->execute();
// insert another row of values
$name = "Joe Public";
$address = "123 main st";
$email = "joe@example.com";
$price = 10.00;
$description = "this is a description";
$created_time = date("Y-m-d H:i:s");
// now execute it to take effect
$result = $stmt->execute();
// insert another row of values
$name = "John Doe";
$address = "999 main st";
$email = "john@example.com";
$price = 30.00;
$description = "this is another description";
$created_time = date("Y-m-d H:i:s");
// now execute it to take effect
$result = $stmt->execute();
echo "New data have been inserted successfully";
}
catch (PDOException $e)
{
echo "Cannot insert data into the database. " . $e->getMessage();
}
?>
<?php
//include all database credential, e.g., $host, $database, $username,
//$password
include("Home/Database/Credential.php");
try
{
$conn = new PDO("mysql:host=$host;dbname=$database", $username,
$password);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch (PDOException $e)
{
echo 'ERROR: Cannot connect to the database. ' . $e->getMessage();
}
//try to create a table if one doesn't exist
try
{
$conn->query("CREATE TABLE IF NOT EXISTS `Products`
(
ID int(6) NOT NULL auto_increment,
ProductNum VARCHAR(8) NOT NULL,
ProductName VARCHAR(35) NOT NULL,
Price DOUBLE(8, 2) NOT NULL,
Image VARCHAR(45),
URL VARCHAR(45) NOT NULL,
Description VARCHAR(64),
PRIMARY KEY (ID),
UNIQUE ID (ID),
// full text searching similar to Google search
FULLTEXT (ProductNum, ProductName, Description)
)
//MySQL 5.7 or higher: InnoDB is the default storage engine but
//consumes more bytes.
//So MyISAM is the preferred choice here/consuming less bytes and
//runs faster.
ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=2 ");
}
catch (PDOException $e)
{
echo 'ERROR: Cannot create a table! ' . $e->getMessage();
}
try
{
$sql = $conn->prepare("INSERT INTO `Products`
(
`ProductNum`, `ProductName`, `Price`, `Image`, `URL`,
`Description`
)
VALUES
(
:ProductNum, :ProductName, :Price, :Image, :URL,
:Description
) ");
$sql->bindParam(':ProductNum', $ProductNum, PDO::PARAM_STR);
$sql->bindParam(':ProductName', $ProductName, PDO::PARAM_STR);
//No PDO::PARAM_DOUBLE OR PDO::PARAM_FLOAT,
//so use PDO::PARAM_STR instead
//all float or decimal # treat as string, eg '12.30'
$sql->bindParam(':Price', $Price, PDO::PARAM_STR);
$sql->bindParam(':Image', $Image, PDO::PARAM_STR);
$sql->bindParam(':URL', $URL, PDO::PARAM_STR);
$sql->bindParam(':Description', $Description, PDO::PARAM_STR);
// now execute it to take effect
$result = $sql->execute();
}
catch (PDOException $e)
{
echo 'Can't insert data into database. ' . $e->getMessage();
}
// Notice that you can place these values after the
// execute() statement as well and as well as
// outside the try ... catch block and it still works.
// logic dictates that you suppose to put these values obtained
// from the POST form before the execute() statement has been called,
// however, in PDO it dispise the logic and allows you to put these
// values after the execute() statement has been called and it
// still work!
if (isset($_POST['num']) && ($_POST['num'] != '') )
{
$ProductNum = $_POST['num'];
}
else
{
$Error = 'You forgot to type in the product number.';
$Flag = true;
}
if (isset($_POST['name']) && ($_POST['name'] != '') )
{
$ProductName = $_POST['name'];
}
else
{
$Error = 'You forgot to type in the product name.';
$Flag = true;
}
if (isset($_POST['price']) && ($_POST['price'] != '') )
{
$Price = $_POST['price'];
}
else
{
$Error = 'You forgot to type the product price.';
$Flag = true;
}
if (isset($_POST['image']) && ($_POST['image'] != '') )
{
$Image = $_POST['image'];
}
else
{
$Error = 'You forgot to type the product image.';
$Flag = true;
}
if (isset($_POST['url']) && ($_POST['url'] != '') )
{
$URL = $_POST['url'];
}
else
{
$Error = 'You forgot to type in the product url.';
$Flag = true;
}
if (isset($_POST['description']) && ($_POST['description'] != ''))
{
$Description = $_POST['description'];
}
else
{
$Error = 'You forgot to type in the product description.';
$Flag = true;
}
?>
<?php
include('Home/Database/connection.php');
try
{
$conn = new PDO("mysql:host=$hostingserver;dbname=$dbname",
$username, $password);
// set the PDO error mode to exception
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch (PDOException $e)
{
echo 'ERROR: Cannot connect to the database. ' . $e->getMessage();
}
try
{
// prepare sql and bind parameters
$stmt = $conn->prepare("INSERT INTO customer_table (firstname,
lastname, email, address)
VALUES (:firstname, :lastname, :email, :address)");
//for placeholders, do like this:
//VALUES (?, ?, ?, ?)");
$stmt->bindValue(':firstname', $firstname, PDO::PARAM_STR);
$stmt->bindValue(':lastname', $lastname, PDO::PARAM_STR);
$stmt->bindValue(':email', $email, PDO::PARAM_STR);
$stmt->bindValue(':address', $address, PDO::PARAM_STR);
//for placeholders, do like this:
//$stmt->bindValue(1, 'firstname', $firstname, PDO::PARAM_STR);
//$stmt->bindValue(2, 'lastname', $lastname, PDO::PARAM_STR);
//$stmt->bindValue(3, 'email', $email, PDO::PARAM_STR);
//$stmt->bindValue(4, 'address', $address, PDO::PARAM_STR);
// insert a row of data
$firstname = "Joe";
$lastname = "Public";
$email = "joe@example.com";
$address = "123 Main St";
$stmt->execute();
// perhaps later, you can insert a new row of data as well
$firstname = "Jane";
$lastname = "Doe";
$email = "jane@example.com";
$address = "666 Main St";
// now execute it to take effect
$stmt->execute();
// perhaps later, you can insert a new row of data as well
$firstname = "Julie";
$lastname = "Johnson";
$email = "julie@example.com";
$address = "777 Main St";
// now execute it to take effect
$result = $stmt->execute();
echo "New records created successfully";
}
catch (PDOException $e)
{
echo "Error: Cannot insert data into the database. " .
$e->getMessage();
}
?>
<?php
include('Home/Database/connection.php');
$customer_name = 'Bill'; # user-supplied data
try
{
$conn = new PDO("mysql:host=$hostingserver;dbname=$databaseName",
$username, $password);
$conn->setAttribute(PDO::ATTR_ERRMODE,
PDO::ERRMODE_EXCEPTION);
}
catch (PDOException $e)
{
echo 'Cannot connect to the database. ' . $e->getMessage();
}
try
{
$data = $conn->query('SELECT * FROM customer_table
WHERE customer_name = ' . $conn->quote($customer_name));
foreach($data as $row)
{
print_r($row);
}
}
catch (PDOException $ex)
{
echo 'ERROR: Cannot select the data. ' . $ex->getMessage();
}
?>
Earlier, the table was being created using the "all-purpse" function query(). As often the case, using prepare() function statement is more robust than using the "all-purpse" function query(). It is strongly recommended that you use prepare() function statement for all of your database programming, including in liu of the "all-purpse" function query() that was illustrated earlier.
In other words, the "all-purpse" function query() illustrated earlier merely for illustration purpose only and not recommended for production. For your every day programming chores, use prepare() function instead.
Let's use prepare() function statement instead of the "all-purpse" function query() to create tables. Here it is:
<?php
//create a table named user_table if it doesn't exist in the database name
try
{
// assuming variable $conn has been initialized with a PDO instance
$sql = $conn->prepare("CREATE TABLE IF NOT EXISTS `user_table`
(
`id` int(10) NOT NULL auto_increment, //id is increment automatically
`name` varchar(25) NOT NULL,
`address` varchar(64),
`email` varchar(64) NOT NULL,
//just to have a variety for demonstrative purpose
`price` float(10, 2), //can be null,10 digits with 2 decimal
`description` text(64), //also can be null
`date_time` timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL,
// the following definitions are advanced uses for key manipulations
PRIMARY KEY (`id`), //used for referring to certain id
UNIQUE KEY `id` (`id`), //for referring to a unique id
// full text searching similar to Google search
FULLTEXT (`name`, `address`, `email`, `description`)
)
//MySQL 5.7 or higher: InnoDB is the default storage engine but
//consumes more bytes.
//So MyISAM is the preferred choice here/consuming less bytes and
// runs faster.
// Optional: DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
// Just put only: ENGINE=MyISAM");
// without the optional: DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci");
// execute the query to create the table
$result = $sql->execute();
}
catch (PDOException $e)
{
echo "Error: Fail to create a table. " . $e->getMessage();
}
?>
There you have it! It is very simple to create a table using prepare() function statement.
To insert data into the table using prepare() function statement, do the following:
<?php
// assuming $conn is an instance of a PDO
// we insert a website's visitors tracking:
// page hits!
// you can replace named parameters (:) below
// with placeholders (?, ?, ?) as well and
// it will work just fine!
// now we prepare the sql statement using named parameters
$stmt = $conn->prepare('INSERT INTO pagecounter(
page_name,
referer,
page_hit
)
VALUE(
:page_name,
:referer,
:page_hit
)
');
// now that the sql statement has been prepared,
// we can go ahead and execute it using actual
// values!
$result = $stmt->execute
(
[':page_name' => $page, ':referer' => $referer, ':page_hit' => '1']
);
?>
Here is a complete site tracking code above that illustrates prepare() function statement using SELECT(), INSERT INTO() and UPDATE() function statements:
<?php
// for a better and secure practice, you should
// put these connection parameters outside of
// this script!
$host = '';
$databaseName = '';
$username = '';
$password = '';
$page = $_SERVER['SERVER_NAME'] . $_SERVER['PHP_SELF'] . '?' .
$_SERVER['QUERY_STRING'];
$referer = $_SERVER['HTTP_REFERER'];
$param = [
':page' => $page,
':referer' => $referer,
':page_hit' => $page_hit
];
try
{
$conn = new PDO("mysql:host=$host;dbname=$databaseName",
$username, $password);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch (PDOException $e)
{
echo 'Cannot connect to the PDO database. ' . $e->getMessage();
}
$sql = $conn->prepare("SELECT * FROM pagecounter
WHERE page_name = :page")
$result = $sql->bindParam(':page', $page);
if ($result)
{
foreach ($result as $row)
{
$counter = $row['page_hit'] + 1;
}
$update = $conn->prepare('UPDATE pagecounter
SET page_name = :page,
referer = :referer,
page_hit = :page_hit
');
// $update->execute([$page, $referer, $counter]);
// or we can make it a cleaner illustration using $param
$update->execute($param);
}
else
{
$stmt = $conn->prepare('INSERT INTO pagecounter(
page_name,
referer,
page_hit
)
VALUE(
:page,
:referer,
:page_hit
)
');
// or you could put the three array items in a variable
// and just put that variable as the argument as well!
$result = $stmt->execute(
[':page' => $page,
':referer' => $referer,
':page_hit' => '1'
]
);
}
// and now we're done, close the database
$conn = null;
?>
<?php
include('Home/Database/connection.php');
//get username and password from user input
$user = $_GET['username']; //e.g.: myuser123
$pass = $_GET['password']; //e.g.: mypass123
try
{
$conn = new PDO("mysql:host=$hostingserver;dbname=$databaseName",
$username, $password);
$conn->setAttribute(PDO::ATTR_ERRMODE,
PDO::ERRMODE_EXCEPTION);
}
catch (PDOException $e)
{
echo 'Cannot connect to the database. ' . $e->getMessage();
}
try
{
$stmt = $conn->prepare("SELECT * FROM membership_table
WHERE username = :username AND password = :password");
// you should make a habbit to use array shortcut: [] instead!
// for example: $stmt->execute([$user, $pass]);
$result = $stmt->execute(array($user, $pass));
//here if you want to know how many rows selected
$rowcount = $result->rowCount();
if ($rowcount > 0)
{
echo($rowcount . ' rows'); // output # of rows selected
}
// set any fetch mode constants: OBJ, NUM, ASSOC, BOTH,
// LAZY, CLASS, etc. Here I use OBJ
$result->setFetchMode(PDO::FETCH_OBJ);
while ($rows = $result->fetch())
{
$username = $rows->username;
$password = $rows->password;
}
}
catch (PDOException $e)
{
echo 'ERROR: Cannot retrieve data. ' . $e->getMessage();
}
?>
<?php
include('Home/Database/connection.php');
//get username and password from user input
$user = $_GET['username']; //e.g.: myuser123
$pass = $_GET['password']; //e.g.: mypass123
try
{
$conn = new PDO("mysql:host=$hostingserver;dbname=$databaseName",
$username, $password);
$conn->setAttribute(PDO::ATTR_ERRMODE,
PDO::ERRMODE_EXCEPTION);
}
catch (PDOException $e)
{
echo 'Cannot connect to the database. ' . $e->getMessage();
}
try
{
//a fancy way of programming but not easy to understand!
$format = sprintf("SELECT * FROM %s
WHERE username = :%s AND password = :%s",
membership_table, username, password);
$stmt = $conn->prepare("$format");
// you should make a habbit to use array shortcut: [] instead!
// for example: $stmt->execute([$user, $pass]);
$result = $stmt->execute(array($user, $pass));
//here if you want to know how many rows selected
$rowcount = $result->rowCount();
if ($rowcount > 0)
{
echo($rowcount . ' rows'); // output # of rows selected
}
// set any fetch mode constants: OBJ, NUM, ASSOC, BOTH,
// LAZY, CLASS, etc. Here I use ASSOC
$result->setFetchMode(PDO::FETCH_ASSOC);
while ($rows = $result->fetch())
{
$username = $rows['username'];
$password = $rows['password'];
}
}
catch (PDOException $e)
{
echo 'ERROR: Cannot retrieve data. ' . $e->getMessage();
}
?>
<?php
include("Home/Database/Credential.php");
try
{
$conn = new PDO("mysql:host=$hostingserver;dbname=$databaseName",
$username, $password);
$conn->setAttribute(PDO::ATTR_ERRMODE,
PDO::ERRMODE_EXCEPTION);
}
catch (PDOException $e)
{
echo 'Cannot connect to the database. ' . $e->getMessage();
}
try
{
$sql = $conn->prepare("SELECT * FROM Products");
$result = $sql->execute();
// set any fetch mode constants: OBJ, NUM, ASSOC, BOTH,
// LAZY, CLASS, etc. Here I use BOTH
$result->setFetchMode(PDO::FETCH_BOTH);
echo '<table>';
while ($rows = $result->fetch())
{
echo '<tr>';
echo '<td>' . $rows->ProductNum . </td>;
echo '<td>' . $rows->ProductName . </td>;
echo '<td>' . $rows->ProductPrice . </td>;
echo '<td>' . $rows[3] . </td>; /* ProductImage */
echo '<td>' . $rows[4] . </td>; /* ProductURL */
echo '<td>' . $rows[5] . </td>; /* ProductDescr. */
echo '</tr>';
}
echo '</table>';
}
catch (PDOException $e)
{
echo 'ERROR: Cannot retrieve data. ' . $e->getMessage();
}
?>
<?php
include('Home/Database/connection.php');
/*
* The Prepared Statements Method
* Best Practice
*/
$cutomer_id = xyz999; //obtained from a user input insecure form
$order_number = 'abc123'; //user-supplied input from an insecure form
try
{
$conn = new PDO("mysql:host=$hostingserver;dbname=$databaseName",
$username, $password);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch (PDOException $e)
{
echo 'Cannot connect to the database. ' . $e->getMessage();
}
try
{
//Initiate the database handshake with mysql by passing the
//query to it
$stmt = "SELECT * FROM customer_table
WHERE order_number like ? AND customer_id like ? ";
# Prepare to retrieve customer's data from database
# using ??????
$stmt = $conn->prepare($stmt);
# Execute the retrieval and binds the palceholders using ?? to
# customer's data (variables)
$result = $stmt->execute(array(
'order_number' => ' . $order_number . ',
'customer_id' => ' . $cutomer_id . '
));
// Affected Rows?
//Like if you want to know how many rows selected?
// Use rowCount() and it is similar to mysql_num_rows()
echo $stmt->rowCount(); // 1 row
// setting mode
$result->setFetchMode(PDO::FETCH_BOTH);
//Or grab values in selected row in resultset using while loop
while ($rows = $result->fetch())
{
$ProductNum = $rows->ProductNum;
$ProductName = $rows->ProductName;
$ProductPrice = $rows->ProductPrice;
$ProductImage = $rows[3];
$ProductURL = $rows[4];
$Description = $rows[5];
}
}
catch (PDOException $e)
{
echo 'ERROR: Cannot retrieve the data. ' . $e->getMessage();
}
?>
<?php
include("Home/Database/Credential.php");
try
{
$conn = new PDO("mysql:host=$hostingserver;dbname=$databaseName",
$username, $password);
$conn->setAttribute(PDO::ATTR_ERRMODE,
PDO::ERRMODE_EXCEPTION);
}
catch (PDOException $e)
{
echo 'Cannot connect to the database. ' . $e->getMessage();
}
try
{
$conn->query("UPDATE Customers_Table
SET Price = 99.95
AND Description = "Men's Suits On Sale"
WHERE ID = ($_POST['id'])");
}
catch (PDOException $e)
{
echo 'ERROR: Cannot update the records. ' . $e->getMessage();
}
?>
<?php
include("Home/Database/Credential.php");
try
{
$conn = new PDO("mysql:host=$hostingserver;dbname=$databaseName",
$username, $password);
$conn->setAttribute(PDO::ATTR_ERRMODE,
PDO::ERRMODE_EXCEPTION);
}
catch (PDOException $e)
{
echo 'Cannot connect to the database. ' . $e->getMessage();
}
try
{
$stmt = $conn->prepare("UPDATE Customers_Table
SET Price = ?,
Description = ?
WHERE ID = ?
");
//And here we're supplying the actual values
$id = 'abc123';
$price = 99.95;
$description = "Men's Suits On Sale";
// And here we're executing the actual binding of values
result = $stmt->execute(array($price, $description, $id));
$affected_rows = result->rowCount();
}
catch (PDOException $e)
{
echo 'ERROR: Cannot update the records. ' . $e->getMessage();
}
?>
Table definitions you learned earlier using the CREATE TABLE syntax are not set in stone. In other words, you're free to alter them at a later date if you need to.
MySQL has SQL commands to let you do commands to alter the original table definitions using the ALTER TABLE command.
It lets you add or delete fields; alter field types; add, remove, or modify keys; alter the table type; and change the table name (among other things).
Typically, you would use phpMyAdmin program to execute these commands. If you rent a web hosting from a third party it usually has phpMyAdmin installed in your database that they provide you. So check with your web hosting vendor for more on the topic of phpMyAdmin.
You can also alter the table definitions in the SQL schema files as well. See an SQL schema file example later on.
Here is a brief screen shot of the phpMyAdmin that I captured it partially to illustrate the command:

As you can see from the example screen shot illustrated above, you can just enter the command in the 'Run SQL query' pane when you click on the 'SQL' menu option at the top and it opens the sql query pane for you to enter the command.
At the bottom of that screen shot there should be a 'Go' button for you to press to send the command to be executed. It got cut off from the illustration above due to a space constraint.
The following examples illustrate the various operations:
To rename a table name bill to a new name of invoice, do the following:
// notice that you would use phpMyAdmin app to execute
// these commands!
// just open up your phpMyAdmin program and type the following
// commands and press 'Go' button in your phpMyAdmin app!
// notice that you can omit the semicolon ";" at the end as well!
// for example: ALTER TABLE bill RENAME TO invoice
ALTER TABLE bill RENAME TO invoice;
Notice that you can omit the the clause 'to' from the command above and it'll works just fine. You can also use RENAME command instead of ALTER command to achieve the same result as above. For example:
// notice that you can omit the semicolon ";" at the end as well!
RENAME TABLE bill TO invoice
Notice that you can omit the the clause 'to' from the command above and it'll works just fine. You can alter (or change) a field name (such as changing your phone category from home phone to cell phone) by doing the following:
// with a semicolon ";" at the end!
ALTER TABLE user CHANGE homephone cellphone VARCHAR (255);
That is correct: there is no TO clause between homephone and cellphone, but you can include it in there if you like.
Notice also that you must specify the column definition "i.e., VARCHAR (255)" when changing a field name in this manner, or else MySQL will generate an error and disallow the operation.
Note also that it is customarily to use VARCHAR type for phone numbers instead of INT type because it is more flexible and allows you and your users to enter special characters as strings, eg., 612-888-1000 or (612)-888-1000.
You can also alter the field property, that is, change the field name tel defined as VARCHAR(30) to a new field named age with a new definition of TINYINT(2). For example:
// change the field name tel defined as VARCHAR(30) to
// a new field named age with a new definition of TINYINT(2)
ALTER TABLE user CHANGE tel age TINYINT(2);
When you CHANGE a field name from one type to another, MySQL will automatically attempt to convert the data in that field to the new type. If the data in the old field is inconsistent with the new field definition--for example, a field defined as NOT NULL contains NULL values, or a field marked as UNIQUE contains duplicate values--MySQL will generate an error.
You can alter this default behavior by adding an IGNORE clause to the ALTER TABLE command that tells MySQL to ignore such inconsistencies.
You can also modify the field size, say changing a 'Username' field, from 10 to 20. For example:
// changing a 'Username' field size from 10 to 20
ALTER TABLE user CHANGE Username Username VARCHAR(20);
Notice also that you don't have to include the first field size value but you have to include the field size value for the second field.
The following demonstrates how to add a new field named salary to the Employee table:
// add a new field named salary to the Employees table
ALTER TABLE Employee ADD salary INT(7) NOT NULL;
You can also delete a field from a table:
// delete a field called 'salary' from a table called 'Employee'
ALTER TABLE Employee DROP salary;
You can also delete a table's primary key:
// delete a table's primary key
ALTER TABLE Employee DROP PRIMARY KEY;
You can also add a primary key to the table. Note that the table must not contain any primary key prior to performing this operation; hence, what's the point in adding a new primary key if one already exists?:
// add a primary key to the table
ALTER TABLE Employee ADD PRIMARY KEY (id);
Note that a table's primary key must always be defined as NOT NULL -- and cannot be defined as NULL.
You can alter the table type by using a TYPE clause in the ALTER TABLE statement. Fore example, the following alters (or changes) the table type from whatever it was defined to a new table type of INNODB.
// alter the table type by using a 'TYPE' clause
// options: INNODB, MYISAM
ALTER TABLE Employee TYPE = INNODB;
You can create tables in a variety of ways based on your own preference. One of the popular ways of doing that is to use SQL file schema. Let's see how to use SQL file schema to create tables.
Basically, you write SQL syntax to create tables like you learned earlier by specifying the table definitions and put those table definition in an SQL file and then import it to your phpMyAdmin application and phpMyAdmin generates the tables for you automatically.
Let's see what it looks like:
// pay attention to the comment syntax which is denoted as: --
// SQL schema uses '--' to specify comments and it won't execute it!
-- you can put any comments on your SQL schema definitions to help
-- you and your readers to identify what you're trying to do!
-- you can customize these SQL schema definitions to suite your objective
-- and then import it to your phpMyAdmin to execute it!
-- just copy these SQL schema definitions into a file and import that file
-- to your phpMyAdmin to execute it!
-- you have to name your file with the .sql extension.
-- try it!
-- Test it by importing the following file: dump.sql to your phpMyAdmin space
-- and see the effect of the schema!
-- Login to your phpMyAdmin account space either live or via a localhost and
-- navigate to your current database!
-- If you have some tables already in your database it should list them in your
-- database! If not, your database contains nothing! An empty space waiting for
-- you to create some tables!
-- At the top of your phpMyAdmin space there should be a bunch of menu items that
-- you can choose to work with your database and among them are 'import' and 'export'
-- buttons for you to click to import/export your schema files!
-- Just follow the on-screen instructions and you'll be fine!
-- There are plenty of tutorials on YouTube on how to import/export schema files!
-- Check it out!
--
-- Here is the start of the schema file!
--
-- SQL schema file: dump.sql
--
-- As you can see these are just comments spits out by phpMyAdmin engine!
--
-- phpMyAdmin SQL Dump
-- version 4.2.10
-- http://www.phpmyadmin.net
--
-- Host: localhost:8889
-- Generation Time: Jan 02, 2015 at 01:44 PM
-- Server version: 5.5.38
-- PHP Version: 5.6.2
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET time_zone = "+00:00";
--
-- Database: `mydb12345` <---- it spits out a database name as well!
--
--
-- From here and on is the actual table definitions!
--
-- You need to create these definitions that suite your objective!
--
-- --------------------------------------------------------
--
-- Table structure for table `comment`
--
-- You can customize this table definition to fit your objective
--
-- Notice that when creating a new table you need to check if an old table
-- already exists!
--
-- If it already exists it will delete it (or drop it from the current database)
--
-- You don't want your outdated old table hiding in your database and messing up
-- your projects and creating bugs!
--
-- If you don't test it and for some reason you happen to have an old table
-- stuck somewhere in your database and this 'CREATE TABLE' command won't create
-- a new table for you as well, making you having to hunt for that old table
-- and trying to delete it while wasting time and having a lot of headach!
--
-- By putting DROP TABLE IF EXISTS `xxx` command, it will delete it for you
-- automatically, saving you time and headach!
--
-- That's why it is a very good habit to always test it before creating a new table!
--
DROP TABLE IF EXISTS `comment`;
CREATE TABLE `comment`
(
`id` int(11) NOT NULL,
`uid` int(11) DEFAULT NULL,
`feed_id` int(11) DEFAULT NULL,
`comment` mediumtext,
`time_stamp` datetime DEFAULT NULL
)
ENGINE=InnoDB AUTO INCREMENT=4 DEFAULT CHARSET=latin1;
--
-- Dumping data for table `comment`
--
-- After creating a table you can insert any initial data as well!
--
-- If there are no initial values to be inserted during the table creation time,
-- there is no need to include an 'INSERT INTO' statement because data is
-- inserted at runtime! Self-explanatory!
-- Notice that the definition for the table `comment` above contains
-- an auto increment command that set to equal to 4 telling phpMyAdmin
-- to auto increment the next id to number 4 because the first 3 rows
-- have been used in the INSERT INTO code below already! See below:
--
-- If you want phpMyAdmin to start the auto increment at a different
-- or higher than number 4, you can change the above AUTO_INCREMENT=4 to
-- whatever number you wish. For example: AUTO_INCREMENT=10.
--
INSERT INTO `comment`
(`id`, `uid`, `feed_id`, `comment`, `time_stamp`)
VALUES
(1, 1, 2, 'sample comment', '2014-11-14 15:05:44'),
(2, 1, 2, 'another sample comment', '2014-11-14 15:05:50'),
(3, 1, 3, 'wow', '2014-11-14 15:40:27');
-- --------------------------------------------------------
--
-- Table structure for table `feed`
--
-- It is a very good habit to always test if a table already exists before creating
-- a new table!
--
DROP TABLE IF EXISTS `feed`;
CREATE TABLE `feed`
(
`id` int(11) NOT NULL,
`uid` int(11) DEFAULT NULL,
`feed_original` longtext,
`feed` longtext,
`feed_url` varchar(500) DEFAULT NULL,
`feed_container` longtext,
`feed_type` varchar(10) DEFAULT NULL,
`time_stamp` datetime DEFAULT NULL,
`view` int(11) DEFAULT NULL
)
ENGINE=InnoDB AUTO INCREMENT=1 DEFAULT CHARSET=latin1;
-- As you can see from the above 'feed' table,
-- if there are no initial values to be inserted during the table creation time,
-- there is no need to include an 'INSERT INTO' statement because data is
-- inserted at runtime! Self-explanatory!
-- Notice that the definition for the table `feed` above contains
-- an auto increment command that set to equal to 1 telling phpMyAdmin
-- to auto increment the next id to number 1 because there isn't any
-- row has been used in the INSERT INTO code! No INSERT INTO clause!
--
-- In this case, we set it to 1 to make phpMyAdmin to start the auto
-- increment with 1.
--
-- If you want phpMyAdmin to start the auto increment at a different
-- or higher than number 1, you can change the above AUTO_INCREMENT=1 to
-- whatever number you wish. For example: AUTO_INCREMENT=5.
--
-- --------------------------------------------------------
--
-- Table structure for table `follower`
--
-- It is a very good habit to always test if a table already exists before creating
-- a new table!
--
DROP TABLE IF EXISTS `follower`;
CREATE TABLE `follower`
(
`id` int(11) NOT NULL,
`uid` int(11) DEFAULT NULL,
`follow_id` int(11) DEFAULT NULL,
`time_stamp` datetime DEFAULT NULL
)
ENGINE=InnoDB AUTO INCREMENT=2 DEFAULT CHARSET=latin1;
--
-- Dumping data for table `follower`
--
-- Notice that the definition for the table `follower` above contains
-- an auto increment command that set to equal to 2 telling phpMyAdmin
-- to auto increment the next id to number 2 because the first row has
-- been used in the INSERT INTO code below already! See below:
--
-- If you want phpMyAdmin to start the auto increment at a different
-- or higher than number 2, you can change the above AUTO_INCREMENT=2 to
-- whatever number you wish. For example: AUTO_INCREMENT=10.
--
INSERT INTO `follower`
(
`id`, `uid`, `follow_id`, `time_stamp`
)
VALUES
(
1, 1, 1, '2014-11-14 15:00:07'
);
-- --------------------------------------------------------
--
-- Table structure for table `likes`
--
-- Notice that as a rule of thumb: DO NOT use plural!
--
-- However, this one is an exception!
--
-- It is a very good habit to always test if a table already exists before creating
-- a new table!
--
DROP TABLE IF EXISTS `likes`;
CREATE TABLE `likes`
(
`id` int(11) NOT NULL,
`uid` int(11) DEFAULT NULL,
`feed_id` int(11) DEFAULT NULL,
`time_stamp` datetime DEFAULT NULL
)
ENGINE=InnoDB AUTO INCREMENT=2 DEFAULT CHARSET=latin1;
--
-- Dumping data for table `likes`
--
INSERT INTO `likes`
(
`id`, `uid`, `feed_id`, `time_stamp`
)
VALUES
(
1, 1, 2, '2014-11-14 15:05:39'
);
-- --------------------------------------------------------
--
-- Table structure for table `notification`
--
-- It is a very good habit to always test if a table already exists before creating
-- a new table!
--
DROP TABLE IF EXISTS `notification`;
CREATE TABLE `notification`
(
`id` int(11) NOT NULL,
`uid` int(11) DEFAULT NULL,
`agent` int(11) DEFAULT NULL,
`target` int(11) DEFAULT NULL,
`action` varchar(20) DEFAULT NULL,
`time_stamp` datetime DEFAULT NULL,
`status` int(11) DEFAULT NULL
)
ENGINE=InnoDB DEFAULT CHARSET=latin1;
-- As you can see from the above 'notification' table,
-- if there are no initial values to be inserted during the table creation time,
-- there is no need to include an 'INSERT INTO' statement because data is
-- inserted at runtime! Self-explanatory!
--
-- --------------------------------------------------------
--
-- Table structure for table `user`
--
-- It is a very good habit to always test if a table already exists before creating
-- a new table!
--
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`
(
`id` int(11) NOT NULL,
`name` varchar(30) DEFAULT NULL,
`address1` varchar(255) DEFAULT NULL,
`address2` varchar(255) DEFAULT NULL,
`city` varchar(255) DEFAULT NULL,
`state` varchar(30) DEFAULT NULL,
`zip` varchar(15) DEFAULT NULL,
`username` varchar(20) DEFAULT NULL,
`password` varchar(255) DEFAULT NULL,
`email` varchar(255) DEFAULT NULL,
`phone` varchar(20) DEFAULT NULL,
`description` varchar(1000) DEFAULT NULL,
`image_type` varchar(10) DEFAULT NULL,
`block` int(10) DEFAULT NULL,
`activation` varchar(10) DEFAULT NULL,
`type` int(10) DEFAULT NULL,
`access` int(10) DEFAULT NULL,
`feed_per_page` int(10) DEFAULT NULL,
`creation_timestamp` datetime DEFAULT NULL,
`lastlogin_timestamp` datetime DEFAULT NULL
)
ENGINE=InnoDB AUTO INCREMENT=4 DEFAULT CHARSET=latin1;
--
-- Dumping data for table `user`
--
INSERT INTO `user`
(`id`, `name`, `address1`, `address2`, `city`,
`state`, `zip`, `username`, `password`, `email`,
`phone`, `description`, `image_type`, `block`,
`activation`, `type`, `access`, `feed_per_page`,
`creation_timestamp`, `lastlogin_timestamp`
)
VALUES
(1, 'Noon2noon', '555 main st', 'apt 10',
'minneapolis', 'mn', '55401', 'user',
'1a1dc91c907325c69271ddf0c944bc72',
'abc@noon2noon.com', '612-404-0778',
'Hey people im a new entry to this website...',
'server', 0, '1', 2, 1, 10, '2017-09-05 23:27:11',
'2017-09-05 23:37:45'
),
(2, 'John Doe', '555 main st', 'apt 10',
'minneapolis', 'mn', '55401', 'john',
'527bd5b5d689e2c32ae974c6229ff785',
'john@doe.com', '612-404-0778',
'Hey people im a new entry to this website...',
'server', 0, '1', 1, 1, 10, '2017-09-05 23:28:04',
'2017-09-07 01:03:42'
),
(3, 'Jane Doe', '555 main st', 'apt 10',
'minneapolis', 'mn', '55401', 'jane',
'5844a15e76563fedd11840fd6f40ea7b',
'jane@doe.com', '612-404-0778',
'Hey people im a new entry to this website...',
'server', 0, '1', 1, 1, 10, '2017-09-05 23:31:11',
'2017-09-07 01:04:01'
);
--
-- Notice that after the table definitions have been created you can
-- alter the definitions if you forgot to include/delete any of the fields.
--
-- For example, the following we can add a primary key to the `comment` table
-- definition earlier because we forgot to create that table to have a primary key.
--
-- Likewise, we add a primary key to the rest of the tables that we forgot to
-- include it in the first place: `feed`, `follower`, `likes`, `notification`, etc.
--
-- Indexes for dumped tables
--
--
-- Indexes for table `comment`
--
ALTER TABLE `comment`
ADD PRIMARY KEY (`id`);
--
-- Indexes for table `feed`
--
ALTER TABLE `feed`
ADD PRIMARY KEY (`id`);
--
-- Indexes for table `follower`
--
ALTER TABLE `follower`
ADD PRIMARY KEY (`id`);
--
-- Indexes for table `likes`
--
ALTER TABLE `likes`
ADD PRIMARY KEY (`id`);
--
-- Indexes for table `notification`
--
ALTER TABLE `notification`
ADD PRIMARY KEY (`id`);
--
-- Indexes for table `user`
--
ALTER TABLE `user`
ADD PRIMARY KEY (`id`);
--
-- AUTO_INCREMENT for dumped tables
--
--
-- AUTO_INCREMENT for table `comment`
--
--
-- For MODIFY and many other SQL commands please checkout the
-- MySQL documentation:
-- https://dev.mysql.com/doc/refman/8.0/en/alter-table.html
--
ALTER TABLE `comment`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO INCREMENT=4;
--
-- AUTO_INCREMENT for table `feed`
--
ALTER TABLE `feed`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO INCREMENT=4;
--
-- AUTO_INCREMENT for table `follower`
--
ALTER TABLE `follower`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO INCREMENT=2;
--
-- AUTO_INCREMENT for table `likes`
--
ALTER TABLE `likes`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO INCREMENT=2;
--
-- AUTO_INCREMENT for table `notification`
--
ALTER TABLE `notification`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
--
-- AUTO_INCREMENT for table `user`
--
ALTER TABLE `user`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO INCREMENT=2;
-- ==============================================================
--
-- Advanced Table Definition Design --
--
--
-- An important note about arranging table definitions in the schema file
--
-- Here is a note for advanced table definition design/creation:
--
-- When you use foreign key to refer to other tables (as the following example shows),
-- you need to put those tables at the top of the tables that is making the reference.
--
-- If you don't, it will give you an error saying:
-- "foreign key cannot reference x table"
--
-- This is because the schema generates the tables sequentially from top to bottom.
-- And when it generates the foreign key and that foreign key references a table that
-- hasn't been generated yet, it can't find that table that the foreign key is
-- referencing. So it will give an error and none of the tables will be created!
--
-- As you can see from the four schema tables below:
--
-- The 'permission' table references the 'rule' table and therefore the 'rule'
-- table has to be on the top of the 'permission' table. Otherwise, it will give
-- an error!
--
-- Likewise, 'parent_child' table and 'assignment' table (both) are referencing
-- the 'permission' table and therefore the 'permission' table has to come before
-- the 'parent_child' and 'assignment' tables.
--
-- Otherwise, it will give an error!
--
--
-- Clear all databases if exist so that we can have fresh databases--a good practice.
--
drop table if exists `rule`;
drop table if exists `permission`;
drop table if exists `parent_child`;
drop table if exists `assignment`;
-- --------------------------------------------------------
--
-- Table structure for table `rule`
--
create table `rule`
(
`name` varchar(64) not null,
`data` text,
`created_at` integer,
`updated_at` integer,
primary key (`name`)
) engine InnoDB;
--
-- Table structure for table `permission`
-- This table references `rule`(`name`) table on delete set null on update cascade
--
create table `permission`
(
`name` varchar(64) not null,
`type` integer not null,
`description` text,
`rule_name` varchar(64),
`data` text,
`created_at` integer,
`updated_at` integer,
primary key (`name`),
foreign key (`rule_name`) references `rule` (`name`)
on delete set null
on update cascade,
key `type` (`type`)
) engine InnoDB;
--
-- Table structure for table `parent_child`
-- This table references `permission` (`name`) table on delete cascade
-- on update cascade
--
create table `parent_child`
(
`parent` varchar(64) not null,
`child` varchar(64) not null,
primary key (`parent`, `child`),
foreign key (`parent`) references `permission` (`name`)
on delete cascade
on update cascade,
foreign key (`child`) references `permission` (`name`)
on delete cascade
on update cascade
) engine InnoDB;
--
-- Table structure for table `assignment`
-- This table also references `permission` (`name`) table on delete cascade
-- on update cascade
--
create table `assignment`
(
`item_name` varchar(64) not null,
`user_id` varchar(64) not null,
`created_at` integer,
primary key (`item_name`, `user_id`),
foreign key (`item_name`) references `permission` (`name`)
on delete cascade
on update cascade,
key `auth_assignment_user_id_idx` (`user_id`)
) engine InnoDB;
For many more (other) SQL commands please checkout the MySQL documentation:
MySQL documentation This concludes a brief but effective PDO database introduction. For more, please check out MySQL PHP API: PDO Database. Thanks! (Paul S. Tuon).In this tutorial, there are two parts:
Here is a very simple regex quick reference cheat sheet. For an extended detail description of these regex expression pattern, please see the next section.
| Regex | Description |
| [abc] | Matches a single character: a, b or c |
| [^abc] | Matches any single character but a, b, or c |
| [a-z] | Matches any single character in the range a-z |
| [a-zA-Z] | Matches any single character in the range a-z or A-Z |
| ^ | Matches at the start of the word, string, or line. Example: ^p will match pop, people, propane, etc. |
| $ | Matches at the end of the word, string, or line. Example: p$ will match pop, gossip, setup, etc. |
| \A | Start of string |
| \z | End of string |
. |
A period '.' matches any single character no matter what that character is. |
| \s | Matches any whitespace character |
| \S | Matches any non-whitespace character |
| \d | Matches any digit |
| \D | Matches any non-digit |
| \w | Matches any word character (letter, number, underscore) |
| \W | Matches any non-word character |
| \b | Matches any word boundary character |
| (...) | (...) captures everything enclosed inside (). Note: (...) is typically being used to group the regex pattern and seperate one group of regex pattern from another. For example, matching a date string "10-15-2020":
"/(\d{2})-(\d{2})-(\d{4})/", $902.05: (^$\d)+(\.)\d{,2}, full name: My name is John Doe:
"/My name is ((\w+)\s(\w+))/". The \s matches any space as in between My and name, name and is, is and John, etc. |
| (a|b) | Alternative branches or choices a or b |
| a? | Matches zero or one occurence of a |
| a* | Matches zero or more occurence of a |
| a+ | Matches one or more occurence of a |
| a{3} | Matches exactly 3 occurences of a |
| a{3,} | Matches 3 or more occurences of a |
| a{3,6} | Matches between 3 and 6 occurences of a |
| i | Matches a case insensitive pattern |
| m | Makes dot match newlines |
| x | Ignores whitespace in regex |
| o | Performs #{...} substitutions only once |
The subject of regular expression (or mostly well-known as regex) is very long and extensive and not to mention very complex as well. For example, PHP 5.2.2 introduced two alternative syntaxes (?<name>pattern) and (?'name'pattern). For example:
<?php
/** First, the basic syntax! **/
// To extract the number from a date string: $result[0] = '10-20-2020'
preg_match("/(\d{2})-(\d{2})-(\d{4})/", "10-20-2020", $result)
/**
* To extract the number from a date string with keys: "year", "month", and "day".
*
* Now the array $result will additionally contain matched position 1, 2,
* and 3 as keys "year", "month", and "day", respectively.
*
* $result[0] = '10-20-2020'
* $result['year'] = '2020', $result['month'] = '10', $result['day'] = '20'.
*/
preg_match("/(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})/", "2020-10-20", $result)
preg_match('/(?P.+)/ ', $string, $match); // basic syntax
/** Now the alternative syntax! **/
preg_match('/(?.+)/ ', $string, $match); // alternative
preg_match("/(?'test'.+)/", $string, $match); // alternative
?>
To define a regular expression in PHP, you would enclose your regular expression definition inside the two forward slashes. For example:
<?php
/**
* here, inside /....../ is where you put your regular expression pattern.
* this is for a case-sensitive regular expression pattern to be matched
*/
$regex = '/......./';
// here, the 'i' is for a case-insensitive regular expression pattern to be matched
$regex = '/......./i';
?>
The two forward slashes /..../ are called delimiters or placeholders holding the actual regular expression pattern. They do absolutely nothing except acting as placeholders for the regular expression, and as such, you can actually use other non-regular-expression rare character tokens in place of the two forward slashes /..../.
For example, you could use these non-regular-expression rare character tokens as well: "~", "#", "%", or "@", and even "+" and "`" (back quote) are valid rare character tokens as well. For example:
<?php
/**
* you can replace /....../ with the following rare characters as well:
*/
$regex = '~.......~';
$regex = '#.......#';
$regex = '%.......%';
$regex = '@.......@';
$regex = '+.......+';
$regex = '`.......`';
?>
As if the non-regular-expression rare character tokens listed above are not enough, you can actually use bracket style delimiters as well, where the opening and closing brackets are the starting and ending delimiter, respectively. For example: (), {}, [], and <> are all valid bracket style delimiter pairs. For example:
<?php
$string = 'Any of this individual example is of a correct pattern delimiter';
/**
* you can replace /....../ with the following rare characters as well:
*/
$regex = '(this [is] a (pattern))'; // will match: this is a pattern
$regex = '{this [is] a (pattern)}'; // will match: this is a pattern
$regex = '[this [is] a (pattern)]'; // will match: this is a pattern
$regex = '<this [is] a (pattern)>'; // will match: this is a pattern
?>
As you can see, delimiter characters are not limited to just forward slashes /..../. As a matter of fact, it can be just any character, including Unicode characters as well. However, use them carefully to avoid problems. My suggestion is that to just use two or three of them consistently on your every day programming chores and stick with the same character or characters for the long haul.
Using just one probably my personal preference: forward slashes /..../.
The three most popular among programmers are, of course the forward slashes /..../, the rarily use character tilde ~....~, and the number sign #....# (in that order).
Bracket style delimiters illustrated above, just like any other characters, do not need to be escaped when they are used as meta characters within the pattern, but as with other delimiters they must be escaped when they are used as literal characters. If the delimiter needs to be matched inside the pattern it must be escaped using a backslash.
If the expression pattern contains forward slashes, such as http:// which can be hard to read using /..../, it is a good idea to choose another delimiter (i.e., #....#) in order to increase readability. For example:
<?php
// as you can see, this is very hard to read!
$regex = '/http:\/\//';
// whereas this, it is much easier to read!
$regex = '#http://#';
?>
PHP regular expression is typically being used with PHP's family of preg functions. In other words, to use regular expressions in PHP, you need to use one of PHP's family of preg functions listed below. These functions require you to enclose your expression pattern using the popular two forward slashes /..../ or any of the rare characters listed above.
preg_match() which performs a regular expression match; preg_match_all() which performs a global regular expression match; preg_replace() which performs a regular expression search and replace; preg_grep() which returns the elements of the input array that matched the pattern; preg_split() which plits up a string into substrings using a regular expression; and preg_quote() takes string and puts a backslash in front of every character that is part of the regular expression syntax. preg_quote() escapes regex patterns before they are applied. preg_quote's second parameter may be used to specify the delimiter to be escaped. See examples below.
This is useful if you have a run-time string that you need to match in some text and the string may contain special regex characters (like $ or the literal forward slash /). Here is a preview of a couple of examples to get you warmed up. For example.
<?php
$expression = '$40 for a g3/400';
/**
* preg_quote() function may be used to escape a string for injection into a pattern
* and its optional second parameter can be used to specify the delimiter to be escaped.
* in this case, '/' is the delimiter for the regular expression: /..../
*
* as you can see above, before the expression can be used in the regex, it needs to be
* escaped first by passing in '/' character to preg_quote() to be use as the delimiter
* for the regular expression: /..../
*/
$result = preg_quote($expression, '/');
echo $result;
/**
* This will produce the following result:
*
* $result = '\$40 for a g3\/400'
*/
?>
Here is another example to clarify this further:
<?php
/**
* In this example, preg_quote($expression) is used to keep the asterisks from
* having special meaning to the regular expression. It backslahes them!
*/
$expression = "*very*";
$result = preg_quote($expression, '/');
/**
* as you can see above, before the $expression can be used in the regex, it needs to be
* escaped first by passing in '/' character to preg_quote() to be use as the delimiter
* for the regular expression: /..../
*
* notice that passing in '/' only tells PHP's family of 'preg' functions that you
* intend to use '/' as a delimiter for your actual expression code.
* it doesn't put '/' around the expression itself for you, however!
*/
/**
* This will produce the following result:
*
* $result = "\*very\*";
*/
/**
* Now that the strings have been escaped properly, we can use the
* regex to search and match the strings. For example:
*/
$string = "This book is *very* difficult to find.";
/**
* notice that passing in '/' above only tells PHP's family of 'preg' functions
* (preg_replace() in this case) that you intend to use '/' as a delimiter for your
* actual expression code as the following example shows.
*
* it doesn't put '/' around the expression itself for you, however!
* as you can see below, "/" are put around the actual escaped expression $result
*
* $text contains the whole original string with an italic around the whole string.
*/
$text = preg_replace("/" . $result . "/", "<i>" . $string . "</i>");
?>
preg_quote() is useful if you have a run-time string that you need to match in some text and the string may contain special regex characters (i.e., $ and / in the above example).
Let's see preg_quote() being used with preg_match() to find occurrences of a given URL surrounded by whitespace:
<?php
$url = 'http://example.com/param?test=answer';
/**
* preg_quote escapes the dot, question mark and equals sign in the URL (by default)
* as well as all the forward slashes (because we pass '/' as the $delimiter argument).
*/
$escapeUrl = preg_quote($url, '/');
/**
* as you can see above, before the url can be used in the regex, it needs to be escaped
* by passing in '/' character to preg_quote()
*
* as you can see below, '/' are put around the actual escaped expression $escapeUrl
*/
$regex = '/\s' . $escapeUrl . '\s/';
// $regex is now: '/\shttp\:\/\/example\.com\/param\?test\=answer\s/'
$string = "Bla bla some spaces http://example.com/param?test=answer bla bla some spaces";
preg_match($regex, $string, $match);
var_dump($match);
// array(1)
// {
// [0]=>
// string(48) " http://example.com/param?test=answer " // note a space before/after url
// }
?>
For more information on their usage of these PHP functions, please Google each function individually to learn more about them.
Now that the pre-emptive (preface) illustration and description and background of regex have been shown, let's start learning regex, starting with the basic syntax.
To use regular expressions (also known as regex), first you need to learn the syntax and its tokens. This syntax consists in a series of letters, numbers, dots, hyphens and special signs, which we can group together using different parentheses and place it inside the slashes shown above.
Regular expression syntax characters (also known as tokens) have special meaning within a regular expression, and these tokens are:
Notice that forward slash / is not among this group of tokens even though it is being used as a placeholder for every regular expression pattern. So the two forward slashes / absolutely do nothing except acting as placeholders for the regular expression.
When using these character tokens, you will need to backslash these character tokens whenever you want to use them literally. For example, if you want to match ".", you'd have to write \.; if you want to match "\", you'd have to write \\; if you want to match "^", you'd have to write \^; if you want to match "$", you'd have to write \$, and so on and so forth.
Let's take a look at these character tokens inidividually that make the basic building blocks of a regular expression. We start with meta characters:
<?php
/**
* There are certain situations where you want to match at the beginning or end
* of a line, word, or string. To do this you can use meta characters.
* Two common meta characters are caret '^' which represent the start of the
* string, and the dollar '$' sign which represent the end of the string.
*
* Here, the '^' is a meta character to signify as the starting point of
* a line, word, or string that the regular expression needs to match.
*
* Likewise, the '$' is a meta character to signify as the end point of
* a line, word, or string that the regular expression needs to match.
*
* And together they become:
*/
$regex = '/^....... $/';
/**
* For example, to match all words or strings that start with an 'h' but don't care
* with the rest of the characters are, do this:
*/
$regex = '/^h/';
/**
* so here, if words or strings like house, hour, hearing, or harmony
* come along it will match! but, if words or strings like
* night, match, attach, or each come along it will not match
* because the words or strings don't start with an 'h'.
*
* notice that this search and match is case-sensitive.
* to search and match with case-insensitive use 'i' after the ending slash.
*/
/**
* Likewise, to match all words or strings that end with an 'h' but don't care
* with the rest of the leading characters are, do this:
*/
$regex = '/h$/';
/**
* so here, if words or strings like match, each, or attach come along it will match!
* but, if words or strings like house, hour, or harmony come along it will not match
* because the words or strings don't end with an 'h'.
*/
?>
<?php
/**
* next up is the square brackets [....].
*
* this is called character class.
*
* in mathetmatics gargon, it is called set or characters in a set.
*
* a character class always matches a single character out of a list of specified
* characters (or set).
*
* for example, the expression [abc] matches only a, b or c character in the set
* and nothing else.
*
* what does it mean:
*
* 'a character class always matches a single character out of a list of specified
* characters' ?
*
* what does the above quote mean?
*
* 'matches a single character'? out of a list or set? seriously?
*
* yes, the sentence is a little misleading, and it is very confusing, too.
*
* so the best way to know what it means is to see some examples.
* let's see some examples to help clarify this further.
*/
?>
Now let's see some examples using PHP's preg_match() function. This function is the most commonly used in the world of php regex. It returns a boolean to indicate whether it was able to match.
If you include a variable's name as a third parameter, such as $match in the example below, when there is a match, the variable $match will be filled with an array: element 0 for the entire match, element 1 for the first complete match string/word, element 2 for the second complete match string/word, element 3 for the third complete match string/word, and so on and so forth.
<?php
/**
* notice the use of the character class [....] to look for only 'm' or 'l' in the
* document ($string)
*/
$expression = "/ho[ml]e/";
$string = 'She bought a house near a nursing home which has a hole in the roof';
/**
* Regular expression has two parts: the expression itself, which contains in
* variable $expression, and the strings or text or document or file content that
* you want to search and match. In this case, that document or string is contained
* in variable $string.
*
* Knowing that, we can just go ahead and try to search and match the expression.
*
* As you can see, the expression starts out with the characters 'ho' and it tries
* to match the strings in variable $string: 'She bought a house near a
* nursing home which has a hole in the roof'.
*
* First, it looks in the first word 'She' and it couldn't find 'ho' in
* the word 'She'.
*
* Next, it goes to the next word which is 'bought' and again it couldn't find 'ho'
* there, either.
*
* Next it goes to the next character 'a' and it didn't match 'ho' there, either.
*
* Next it goes to the next character/word 'house' and it matches 'ho' in 'house'.
*
* Now that it found 'ho' in the word 'house', it is done with 'ho' for now.
*
* Now, it must go to the next expression which is inside the class definition [....... ].
*
* Inside the class definition is where it tries to match [m] and [l].
*
* So the next character in the strings to look for is 'm' after the characters 'ho' in
* the word 'house'. But it couldn't find 'm' after 'ho' in the word 'house'.
* It found a 'u'. But that is not what the expression wants.
*
* So it gives up on that partial matched and throws the word 'house' away and moves on.
*
* Now that it gave up the partial matched characters 'ho' in 'house',
* it starts all over again to find 'ho' in other upcoming strings.
*
* Next it goes to the next character/word 'near' and it didn't match 'ho', either.
* So it throws away 'near' and moves on!
*
* Next it goes to the next character 'a' and it didn't match 'ho', either.
*
* Next it goes to the next character/word 'nursing' and it didn't match 'ho', either.
*
* Next, it goes to the next word which is 'home', and lo and behold, it matches the
* characters 'ho' in 'home'. Whoa! we have a match! Well, partially just like 'house'!
* Well, it's a promising start, nonetheless!
*
* Now that it found 'ho' in the word 'home' it goes to the next expression which is
* inside the class definition [....... ].
*
* Inside the class definition is where it tries to match [m] and [l].
*
* The next character in the strings to look for is 'm' after the characters 'ho' in
* the word 'home'.
* And it found 'm' in the word 'home' but couldn't find the character 'l' in the
* word 'home'.
*
* Had $string contains a word like 'homlet' it would have matched both 'm' and 'l',
* partially.
*
* Well, why stop there? We can design more sophisticated pattern to match as well.
*
* Let's assume that inside the [...] contains a pattern like [m | l]--an alternative
* match choosing one or the other but not both of them.
*
* So what is the outcome of the expression?
*
* In other words, if $string contains 'homlet', will there be a matched?
*
* No, there will not be a matched because the pattern only goes inside the [] once
* to choose either an 'm' or an 'l' and not both of them like the one used earlier.
*
* Here is what it does: after matching 'ho' it tries to choose only one character
* from inside the []. It looks for both 'm' and 'l' but it decided to choose 'm' and
* not 'l'. And it moves on to match outside of the [] and never come back to look
* at 'l' again because it already looked at 'l' earlier and decided that it didn't
* like 'l'.
*
* Do you see the difference between this pattern and the one used earlier?
*
* Okay, let's get back to the original pattern [ml] and try to finish the matching.
*
* Nevertheless, it is satisfied with the search at this point where 'hom' for word
* 'home' have been matched partially! And it moves on!
*
* So now it is done matching inside the brackets [] where it has already matched 'hom'
* and tries to go outside of the class definition [....... ].
*
* Now it tries to look for a character 'e' in the word 'home' after matching 'hom'.
*
* And this time, it found the character 'e' in the word 'home' after matching 'hom'
* in the word 'home'. We found a complete matched!
*
* Now since it found a complete matching word in 'home', preg_match(), then, puts
* 'home' in an array variable $match[1].
*
* Now that it is done with the word 'home', it starts all over again to find 'ho' in
* other upcoming strings or document.
*
* Remember that all words/characters in the document must be searched and tried
* to match.
*
* So next, it goes to the next word in sequence, which is the word 'which' and it
* couldn't find the characters 'ho' (for 'hole') there, either.
*
* Remember that the expression wants any document that starts with 'ho', followed
* by either an 'm' or an 'l' or both if there are both characters in the $string that
* has an 'm' followed by an 'l', and then followed by an 'e'. That's what it wants!
*
* Is there any word in the document that fits such criterio? Yes, there is: 'hole'.
*
* We'll have to just continue looking for it until we find it.
*
* Next, it goes to the next word in sequence until it find the characters
* 'ho' for 'hole'. I won't run down the steps to complete the next search and match.
*
* And it does the same sequence for 'hole' as it does when it tries to match
* the word 'home'. Self-explanatory! I'll leave the rest for you to complete!
*
* After that, when it found a complete matching word 'hole', preg_match() puts
* 'hole' in an array variable $match[2].
*
* preg_match() also puts all of the matching words in sequence ('home hole') in an array
* variable $match[0].
*
* array: element 0 for the entire match (i.e., 'home hole'), element 1 for the first
* complete match string/word (i.e., 'home'), element 2 for the second complete match
* string/word (i.e., 'hole'), element 3 for the third complete match string/word,
* and so on and so forth.
*/
if (preg_match($expression, $string, $match))
{
// $match[1] = 'home' and match[2] = 'hole'
echo "Match found: " . $match; // $match[0] = 'home hole'
}
else
{
echo "Match not found.";
}
?>
As often the case, the more examples there are the better off we are in understanding things. For that reason, let's see some more examples using PHP's preg_match() function to get a better feeling. This time, we'll use bracket characters ().
<?php
$string = 'Any of this individual example is of a correct pattern delimiter';
/**
* you can replace /....../ with the bracket characters () as well, for example:
*/
$regex = '(this [is] a (pattern))'; // it will try to match: this is a pattern
/**
* As you can see, the expression starts out with a string/word character 'this'
* and it tries to match any word/string in the variable $string:
*
* 'Any of this individual example is of a correct pattern delimiter'
*
* First, it looks in the first word 'Any' and it couldn't find the word 'this'.
*
* Next, it goes to the next word which is 'of' and again it couldn't find the word
* 'this' there, either.
*
* Next, it goes to the next word/string which is 'this' and this time it found
* the word/string 'this'.
*
* Now since it found a complete matching word/string 'this', preg_match(), then, puts
* 'this' in an array variable $match[1].
*
* Now since it found a complete matching string in 'this' it is done with that expression.
*
* Next, it goes to the next expression in sequence which is inside the [].
*
* Inside the [] contains the string 'is' which the expression tries to look for in $string.
* Since it is a new sequence, it must starts matching from the beginning of the $string.
*
* Knowing that, it goes to the first word in sequence which is 'Any' and again it couldn't
* find the word 'is'.
*
* Next, it tries to find the word 'is' in the next word in $string which is 'of' and it
* couldn't find the word 'is' there, either.
*
* Next, it goes to the word in sequence which is 'this' and again it couldn't
* find the word 'is' there, either.
* Notice that even though the word 'this' matched the word 'is' partially, but it has to
* be the whole word by itself and not part of the word like th~is~. So it's not a matched!
*
* Next, it continues to find the word 'is' in sequence which is 'individual' and again it
* couldn't find the word 'is' there, either.
*
* Next, it continues to find the word 'is' in sequence which is 'example' and again it
* couldn't find the word 'is' there, either.
*
* Next, it continues to find the word 'is' in sequence which is 'is' and this time,
* it found the word 'is' there, and preg_match(), then, puts 'is' in an array
* variable $match[2].
*
* Now since it found a complete matching string in 'is' it is done with this expression.
*
* Next, it goes to the next expression in sequence which is outside the [].
*
* Outnside the [] contains the next string 'a' which the expression tries to look for in
* $string.
*
* Now since it is a new sequence, it must starts matching from the beginning of the $string.
*
* Knowing that, it goes to the first word in sequence which is 'Any' and again it couldn't
* find the string 'a' there, either.
*
* Next, it tries to find the string 'a' in the remaining upcoming word/string in $string
* until it finds the string 'a' or the end of $string.
*
* Eventually, it will find the string 'a' and preg_match(), then, puts 'a' in an array
* variable $match[3].
*
* Next, it continues to find the word/string in sequence until the expression is
* completely exhausted and done!
*
* Eventually, it will find the string 'pattern' and preg_match(), then, puts 'pattern' in
* an array variable $match[4].
*
* Now since the expression is completely exhausted and done, preg_match(), then, puts
* all of the matched strings in sequence in array variable (element 0): $match[0].
*
* array: element 0 for the entire match (i.e., 'this is a pattern'), element 1 for the
* first complete match string/word (i.e., 'this'), element 2 for the second complete
* match string/word (i.e., 'is'), element 3 for the third complete match string/word
* (i.e., 'a'), element 4 for the fourth complete match string/word (i.e., 'pattern'),
* and so on and so forth.
*/
if (preg_match($regex, $string, $match))
{
// $match[1] = 'this', match[2] = 'is', match[3] = 'a', match[4] = 'pattern'
echo "Match found: " . $match; // $match[0] = 'this is a pattern'
}
else
{
echo "Match not found.";
}
?>
Let's see some more examples using PHP's preg_match() function to get even a better feeling.
<?php
$expression = "/\b(\d+)\s*(\w+)$/";
$string = 'Give me 100 dollars';
/**
* Regular expression has two parts: the expression itself, which contains in
* variable $expression, and the strings or text or document or file content that
* you want to search and match. In this case, that document or string is contained
* in variable $string.
*
* Knowing that, we can just go ahead and try to search and match the expression.
*
* As you can see, the expression starts out with a word boundary character \b
* to match any word in the variable $string: 'Give me 100 dollars'
*
* Now inside the () contains \d (which is any digit) and + (which is one or more).
* Together, they mean match any digit with one or more of the digits.
*
* First, it looks in the first word 'Give' and it couldn't find one or more digits in
* the word 'Give'.
*
* Next, it goes to the next word which is 'me' and again it couldn't find one or more
* digits there, either.
*
* Next, it goes to the next word/string which is '100' and this time it found one or
* more digits in the word/string '100'.
*
* Now since it found a complete matching word/string in '100', preg_match(), then, puts
* '100' in an array variable $match[1].
*
* Now since it found a complete matching string in '100' it is done with the boundary
* word matching and it needs to move on to the next expression in sequence which is \s*.
* '\s' matches any whitespace character (space, tab, newline or carriage return character).
* Same as [\t\n\r]. * signifies as zero or more (or in this case, zero or more spaces).
*
* So after '100' it found a space and it is a matched! It is satisfied and moves on!
*
* Next, it goes to the next expression in sequence which is inside the ().
*
* Inside the () contains \w (which is any word) and + (which is one or more).
* Together, they mean match any word with one or more of the words.
*
* Knowing that, it goes to the next word in sequence which is 'dollars' and again it
* found one word in 'dollars'. It is satisfied with the matched and moves on to $ which
* signifies as the ending of any word, 'dollars' in this case. It is done matching!
*
* Now since it found a complete matching word in 'dollars', preg_match(), then, puts
* 'dollars' in an array variable $match[2].
*
* preg_match() also puts all of the matching words in sequence ('100 dollars') in an array
* variable $match[0].
*/
if (preg_match($expression, $string, $match))
{
echo "1st match found: " . $match[1] . "<br />"; // $match[1] = '100'
echo "2nd match found: " . $match[2] . "<br />"; // $match[2] = 'dollars'
echo "The whole match found: " . $match[0] . "<br />"; // $match[0] = '100 dollars'
}
else
{
echo "Match not found.";
}
?>
You can use these examples as the basic starting point for your own expression design to match sophisticated expression patterns for your own projects. Just play around with it using different character tokens and mixing them up with other character tokens to be discussed later like the predefined character classes, repetition quantifiers, pattern modifiers, position meta characters, and word boundaries.
<?php
/**
* meta characters like '^' and hyphen '-' can be inside the brackets [.......] as well.
*
* the ^ inside the [.......] is used to negate the expression.
* for example, to match any character in the expression except those contained
* within the brackets [.......], you use the meta character ^ after the opening bracket [.
* for example, the following matches any character except 'x', 'y', or 'z'.
*/
$regex = '/[^xyz]/';
/**
* notice that when used outside of the brackets [....], '^' still signifies as the
* start of the word or strings.
*/
* inside the brackets [.......] meta character hyphen '-' is used to define
* character range, like [0-9] or [a-z] or [A-Z].
*
* for examples:
*/
// it matches any digit between 0 and 9, inclusive
$regex = '/[0-9]/';
// it matches any letter between a and z, inclusive
$regex = '/[a-z]/';
// it matches any letter between k and s, inclusive
$regex = '/[k-s]/';
/**
* it matches any digit between 0 and 9, inclusive, or also,
* it matches any upper case letter or lower case letter between
* a or A (both inclusive) and z or Z (both inclusive), respectively.
*/
$regex = '/[0-9a-zA-Z]/';
/**
* next up is '|' to signify the alternate of the character definition.
* it is a multiple choice route to go, e.g.:
* Foo | Bar | Caz | Daz with four choices to match only one: Foo or Bar or Caz or Daz
*/
$regex = '/Foo | Bar/' /** so if it finds Foo or Bar, it's a matched! **/
// likewise,
$regex = '/a | b/' /** so if it finds an 'a' or a 'b', it's a matched! **/
/**
* note that meta characters like '^', '$', '|', or any other meta characters for that
* matter, can be used inside or outside of the character class definition [....... ].
*/
?>
Note that forward slash / is not a special regular expression character.
<?php
/** A summary of meta characters class definition: **/
// to find and match any one of the characters a, b, or c.
$regex = '/[abc]/';
// to find and match any one character other than a, b, or c.
$regex = '/[^abc]/';
// to find and match any one character from lowercase a to lowercase z.
$regex = '/[a-z]/';
// to find and match any one character from uppercase A to uppercase Z.
$regex = '/[A-Z]/';
// to find and match any one character from lowercase a to uppercase Z.
$regex = '/[a-Z]/';
// to find and match a single digit between 0 and 9.
$regex = '/[0-9]/';
// to find and match a single character between a and z or between 0 and 9.
$regex = '/[a-z0-9]/';
?>
Some character classes such as digits, letters, and whitespaces are used so frequently that there are shortcut names for them. The following table lists those predefined character classes:
| Shortcut | Description |
. |
That is a period '.' It matches any single character except newline \n. The period '.' has a special meaning within a regular expression in that it represents any character -- it's a wildcard. To represent and match a literal '.' it needs to be escaped which is done via the backslash \, i.e., \.
The ' /p /^ /<b>( |
\d |
Matches any digit character. Same as For instance, you can search for large sum of money using the ' |
\D |
Matches any non-digit character. Same as [^0-9] |
\s |
Matches any whitespace character (space, tab, newline or carriage return character). Same as [ \t\n\r] |
\S |
Matches any non-whitespace character. Same as [^ \t\n\r] |
\w |
Matches any word character (definned as a to z, A to Z,0 to 9, and the underscore). Same as [a-zA-Z_0-9] |
\W |
Matches any non-word character. Same as [^a-zA-Z_0-9] |
'.' Matches (Almost) Any CharacterIn regular expressions, the dot '.' or period is one of the most commonly used meta characters. Unfortunately, it is also the most commonly misused and misunderstood meta character.
So what exactly is a dot '.' meta character or how do we suppose to use it correctly?
First of all, the dot '.' matches a single character, without caring what that character is. For example, the expression \d{1,} tells us to match any single character and it doesn't matter what that character is except line break characters. As long as the individual character being match is not some form of line break characters, it is fine.
So the expression above could be any digit (i.e., $12345.00) depending what the strings to be matched is. Notice the use of the dot '.' literal character. See examples later to get a better view of it.
Secondly, as noted above, the dot '.' does not match line breaks by default. This exception exists mostly because of historic reasons. The first tools (in the old days) that used regular expressions were line-based. They would read a file line by line, and apply the regular expression separately to each line.
The effect is that with these (old) tools, the string could never contain line breaks, so the dot '.' could never match them. It makes a lot of sense to not trying to match line breaks because it is very difficult to visualize exactly where the line breaks are, even with trained eyes, you couldn't possibly spot line breaks in today's text.
In the previous section we've learnt how to match a single character in a variety of fashions. But what if you want to match on more than one character? For example, let's say you want to find out words containing one or more instances of the letter p, or words containing at least two p's, and so on.
This is where quantifiers come into play. With quantifiers you can specify how many times a character in a regular expression should match.
The following table lists the various ways to quantify a particular pattern:
| Symbol | Description |
+ |
Matches one or more. E.g., p+ matches one or more occurrences of the letter p. |
* |
Matches zero or more occurrences. E.g., p(hp) |
? |
Matches zero or one occurrence and not more. E.g., p? matches zero or one occurrences of the letter p. This is matching no more than one occurence--either matching one or none at all. |
{} |
Matches exactly the specified number of occurrences. E.g., p{3} matches exactly three occurrences of the letter p. |
{,} |
Matches at least the specified occurrences before the comma, but not more than the specified occurrences after the comma. E.g., p{3,2} matches at least three occurrences of the letter p (and it can be more), but not more than two occurrences of the letter p (specified after the comma). |
{2,} |
Matches two or more occurrences (or at least two) occurrences. The un-specified number after the comma tells it that it is open to as much as it can be. |
{,3} |
Matches at most the specified number of occurrences after the comma, but not more than the specified occurrences specified after the comma. E.g., p{,3} matches at most three occurrences of the letter p and not more than three occurrences of the letter p (specified after the comma). |
^ |
'^' is a meta character to signify as the starting point of a line, word, or string that the regular expression needs to match. For example, ^p matches any string with p at the beginning of it. All these words will result in a match: people, pop, preference, procedure. |
$ |
'$' is a meta character to signify as the ending point of a line, word, or string that the regular expression needs to match. For example, p$ matches any string with p at the end of it. All these words will result in a match: group, pop, up, gossip. |
[[:alpha:]] |
It matches any string containing alphabetic characters aA through zZ. |
[[:digit:]] |
It matches any string containing numerical digits 0 through 9. |
[[:alnum:]] |
It matches any string containing alphanumeric characters aA through zZ and 0 through 9. |
[[:space:]] |
It matches any string containing a space. |
A pattern modifier allows you to control the way a pattern match is handled. Pattern Modifiers can be used either inline or as flags. For example, to search and match case-insensitive expression, you can use the "i" modifier in two ways:
flag at the end of the pattern: /Color/i. This will match the string 'color'.Inline at the start of the pattern: /(?i)Color/. Likewise, this will match the string 'color'.Inline modifier syntax, you can turn off part of the string (for instance, (?-i) turns off the case-insensitive modifier).
The following table lists some of the most commonly used pattern modifiers.
| Symbol | Description |
| /regex/ | My convention: Note that 'regex' is my placeholder used for the actual regular expression. For example, /color/i is in 'regex'. | i |
Makes the match case-insensitive manner. For example, $expression = "/color/i" will match the word color or Color or cOlor or coLoR. |
m |
If you have a string (or document that you want to search and match) consisting of multiple lines, like You can use
The "start of line" metacharacter ( If there are no "\n" characters in a string document, or no occurrences of |
g |
Perform a global match, i.e., finds all occurrences. |
o |
Evaluates the expression only once. |
s |
\s matches a space, a tab, a carriage return, a line feed, or a form feed. It matches any whitespace character (space, tab, newline or carriage return character). Same as [ \t\n\r] |
x |
When using In other words, The
$expression = "/ # this is a comment inside the expression
(?x)regex # this is the regular expression pattern
# make note of the 'x' modifier!
/imx";
The pattern $expression = "/(?x)regex/" will make the remainder of the 'regex' free of whitespaces like spaces, tabs, and line breaks. In other words, any whitespace contains in 'regex' will be ignored and not trying to match. For example, x modifier nullify this behavior. |
You can embedd comments inside regular expression using an unescaped # character outside a character class. The comments can continue up to the next newline character in the pattern. In other words, comments are line-basis similar to php's comment directive '//' where a comment can stretch only in a line. To use multi-line comments similar to PHP's /** .... */ use '(?#' which marks the start of a comment which continues multiple lines up to the next closing parenthesis. Nested parentheses are not permitted. For example:
<?php
$string = 'test';
/**
* this is a multi-line comment inside a regular expression pattern
*/
$expression = '/te(?# this is inside a multi-line comment)st/';
echo preg_match($expression, $string) . "\n";
// this is a single-line comment that stretches over to two lines!
$expression = '/te#~~~~
st/';
// this is illegal! cannot stretch more than one line!
echo preg_match($expression, $string) . "\n";
/** this is a single-line comment that stretches over to two lines!
* however, there is an x modifier which allows us to put our regex on
* several lines.
*/
$expression = '/te#~~~~
st/x';
// this is legal! make note of the 'x' modifier in the expression above!
echo preg_match($expression, $string) . "\n";
// result
// 1
// 0
// 1
Now let's see some more examples and this time using PHP's preg_match_all() function.
preg_match_all('document', 'expression') searches 'document' for all matches to the regular expression given in 'expression' and puts them in matches in order of the match. For example, $document = 'this is a string' and assuming the whole string in $document is matched, preg_match_all() puts match[0] = 'this is a string' with the first matched string being 'this', the second being 'is', the third being 'a', and the last being 'string'.
If there are more matching strings in the $document, it will continues to put them in the order until it is exausted with the matching.
In other words, after the first match is found in the $document, the subsequent searches are continued on from the end of the last match, while at the same time, putting them in the order until it is exausted with the matching.
The following example will show you how to perform a global case-insensitive search using the i modifier and the PHP preg_match_all() function.
<?php
/**
* here, it disregards any uppercase letter and treats them as lowercase letter
* so it found two matches: one with an uppercase letter 'Color' and another
* with a lowercase letter 'color'.
*/
$expression = "/color/i";
$text = "Color red is more visible than color blue in daylight.";
$match = preg_match_all($expression, $text, $array);
echo $match . " matches were found."; // 2 matches were found.
?>
Now let's see some more examples using PHP's preg_match_all() function.
<?php
/**
$expression = "/\d+(,\d+)*/";
$list = "1,2,3,4";
$match = preg_match_all($expression, $list, $match);
print_r($match);
/**
Output:
Array
(
[0] => Array(
[0] => 1,2,3,4
)
[1] => Array(
[0] => ,4
)
)
Now let's see some more examples using PHP's preg_match_all() function. The the following example shows how to match at the beginning of every line in a multi-line string using meta character ^ and character modifier m with PHP preg_match_all() function.
<?php
/**
* here, we know that '^' matches at the beginning of the line of the string,
* for example, ^p matches: people, Peterson, pepper, pop, but not epsilon nor setup.
* however, if 'i' was not included here, Peterson would not have been matched.
* or in the case below, the uppercase 'Color' would not have been matched.
*
* as you can see, the new line command: \n cuts the line into two with a
* new line starting with a lowercase letter 'c' in 'color'.
* had that new line command is not there, there would be only one matched.
*/
$expression = "/^color/im";
$text = "Color red is more visible than \ncolor blue in daylight".;
$match = preg_match_all($expression, $text, $array);
echo $match . " matches were found."; // 2 matches were found.
?>
Now let's see some more examples using PHP's preg_match() function.
<?php
/**
* here, we start with a dot '.' enclosed inside the parenthesese to match any single
* character except line breaks. this can be any character and in conjunction with ()
* to group the matched characters activated by the + we can match a lot of characters
* in a long line. for example, 'Joe the six pack has gone home!'
*
* next, we have an expression: \. to tell us that we want the literal '.'.
*
* next, we have an expression: [php] to tell us that we want to match a 'p',
* an 'h', or a 'p' to form it as 'php'.
*
* as you might have guessed, the expression could turn out to be like this:
*
* 'Joe the six pack has gone home!.php'
*
* which is a weird php file name. hey, this is not about trying to match a
* php file name. it is about learning how to use dot '.' correctly.
*/
$expression = "/(.)+\.[php]/";
/** alright, let's see some more examples using dot '.' **/
/[0-9]\.[ab]/ <--- this will match a digit, a period, and "a", or "b", or "ab",
but not "ba"
/[0-9].[ab]/ <--- this will match a digit, any single character, and
"a", or "b", or "ab", but not "ba". I.e., '8Ka' or '8Kb' or '8Kab'
/[^\.])\.[^\.]/ <--- matches any single character and a '.' between them
/**
* notice the '^' negation meta character to negate the '\.' which
* means '\.' turns into '.' and as such, it matches any single character.
* so it matches any single character, followed by a '.', followed by any
* single character. Example: 'J.k'
*/
/**
* backslash is typically being used to escape characters. for example,
* to match the regular expression tokens: . * ? + [ ] ( ) { } ^ $ | \
* you will need to backslash (or escape) them whenever you want to use them literally.
*
* For example, if you want to match ".", you'd have to write \.;
* if you want to match "\", you'd have to write \\; if you want to match "^",
* you'd have to write \^;
* if you want to match "$", you'd have to write \$, and so on and so forth.
*
* We know that to use "\" literally, we have to escape it like this \\.
*
* What about double slashes?
*
* Well, if we escape the single slash like this \\, then to escape the double slashes,
* we can just repeat the single slash escaped mode with one more time to make it a
* double slashed escape mode.
*
* Simple enough?
*
* In other words, if we want to match "\\", we have to write \\\\.
*
* Right here where it gets a little confusing using single and double quotes on
* single and double slashes!
*
* Single and double quoted PHP strings have special meaning on single backslash
* and double backslashes.
*
* PHP uses backslash as an escape character in double-quoted string, too.
*
* Thus if \ has to be matched with a regular expression \\, then "\\\\" or
* '\\\\' must be used in in your regex code.
*
* In other words, to match \\ inside either single or double quotes, '\\\\' must
* be used in your regex code.
*
* In these cases you'll need to double the escape:
*/
$single = '\.'; // here, $single = '.' <--- notice the same as double quotes!
$double = "\\."; // here, $double = '.' <--- notice the same as single quote!
So this: "/\$\d{1,}./" i.e., $9001234050 <--- notice that no dot '.' at the end!
how about this: '/\$\d{1,}\./' i.e., $9001234050. <--- notice the dot '.' at the end!
or it could be written as this as well: "/\\$\\d{1,}\\./" i.e., $9001234050. <--- dot '.'
/** let's see some explanations **/
/**
* now we know that '$' matches characters at the end of the string.
* but in the expression below, we're escaping $ to output the actual $ and not
* performing a meta search with $. so this is a literal $ to output $ as in $12345.00.
* next, we have an expression: \d{1,}. with \d represents any digits and {1,} tells
* us to match at least one or more digits. it can be a lot of digits but it has to be
* at least one digit.
* now the period '.' tells us to match any single character except newline \n.
* so now the result could be something like this: $12345
*/
$expression = "/\$\d{1,}./";
// how about this:
$expression = '/\$\d{1,}\./';
/**
* this is the same thing as first version except the escaping of the literal period '.':
* escaping $ to output the actual $ and not performing a meta search with $
* next, we have an expression: \d{1,}. with \d represents any digits and {1,} tells us
* to match at least one or more digits.
* now the escaped period '\.' tells us to match the actual literal character '.'.
*
* in other words, we want to display the literal '.' "as is", i.e, $12345.00.
* now the result could be something like this: $12345. <-- notice the dot '.' at the end.
*/
$expression = "/\\$\\d{1,}\\./";
$string = '$12345.';
/**
* so what exactly are we trying to do, here?
*
* here and above, we have a variable $expression that holds an expression and we also
* have a variable $string to match the pattern contains in $expression.
*
* think of it this way:
*
* $expression is a rule or a specification and $string is a finished product.
*
* now we want to match the finished product with the specification to see
* if it meets the rule or the specification.
*
* that's what we're trying to do--to replace the expression pattern with the given
* strings: '$12345.' to see if it meets the specification using preg_replace().
*/
echo preg_replace($expression, $string, $match);
/**
* now what if we have $string containing this: $string = '$12345' ?
*
* will it match? Answer: no, because the specification says you have to have
* a dot '.' at the end of the strings.
*
* likewise, what if we have $string containing this: $string = '12345' ?
*
* will it match? Answer: no, because the specification says you have to have
* a '$' at the beginning of the strings.
*/
?>
Now let's see some more examples using both PHP's preg_replace() and str_replace() functions.
<?php
$expression = "/\s/";
$replacement = "-";
/**
* here, using preg_replace(), every time it sees a white space or spaces,
* a new line or lines, a tab or tabs it will replace them with hyphen '-'.
* consider this text to use with the regular expression replace preg_replace():
*/
$text = "The night is\nstill\tyoung!";
/**
* Replace spaces, newlines and tabs
* this will output: The-night-is-still-young!
*/
echo preg_replace($expression, $replacement, $text);
echo "<br>";
/**
* Replace only spaces but not line break nor tabs
* here, using str_replace(), every time it sees a white space or spaces,
* it will replace them with hyphen '-'.
* this will output: The-night-is still young!
*/
echo str_replace(" ", "-", $text);
?>
Now let's see some more examples and this time using PHP's preg_split() function.
<?php
/**
* here, every time it sees a whitespace, comma, sequence of commas, or combination thereof,
* it will split the string at those points using the PHP preg_split() function.
* notice the use of the '+' to match one or more occurrences of a whitespace, comma,
* sequence of commas, or combination thereof.
*/
$expression = "/[\s,]+/";
$text = "My favorite colors are red, green and blue";
$part = preg_split($expression, $text);
/**
* now $part[0] = 'My', $part[1] = 'favorite', $part[2] = 'colors', $part[3] = 'are',
* $part[4] = 'red', $part[5] = 'green', $part[0] = 'blue'
*/
// Loop through part array and display substrings
foreach ($part as $piece)
{
echo $piece . ", "; // output: My, favorite, colors, are, red, green, blue
}
?>
^' which represent the start of the string, and the dollar '$' sign which represent the end of the string.
Now let's see some more examples and this time using PHP's preg_grep() function.
<?php
/**
* here, it looks for strings that start with the letter 'F' using meta character '^'
*
* that is it! very simple!
*/
$expression = "/^F/";
$string = ["Quarterback", "Clark Kent", "Fred Kruger", "James Bond", "Flow Chart",
"Fire Truck"];
$match = preg_grep($expression, $string);
// Loop through an array of strings and display matched strings
foreach ($match as $value)
{
echo $value . ", "; // output: Fred Kruger, Flow Chart, Fire Truck,
}
/**
* here, it looks for strings that end with the letter 'k' using meta character '$'
*
* that is it! very simple!
*/
$expression = "/k$/";
$string = ["Quarterback", "Clark Kent", "Fred Kruger", "James Bond", "Flow Chart",
"Fire Truck"];
$match = preg_grep($expression, $string);
// Loop through an array of strings and display matched strings
foreach ($match as $value)
{
echo $value . ", "; // output: Quarterback, Fire Truck,
}
?>
Remember that regular expression contains only these character tokens:
But to match partial words, we need a way to specify boundaries where words are located. Hence, word boundaries are 'words' like cart, carrot, cartoon, etc. -- words that have multiple sylables.
But to match partial words, we have to put words in the regular expression that contains other characters used by the character tokens. In other words, how do we differentiate between the boundary words and the characters that the character tokens are performing on?
For example, consider this:
On the left is an ordinary pattern matched by the character tokens and on the right is supposed to be a boundary word to be matched.
So, how do we differentiate between the characters [on the left] that the character tokens are performing on and the boundary word on the righ? How do we differentiate them? We can't! It's all a mess!
This is where boundary characters come in. So we need boundary characters like \b, \w and as well as literal tokes \d, \o, \x, etc. Now, how do we differentiate them? You guessed it: \ to escape the b. Now we can put \b and \w in the mixed with the rest of the character tokens and they all are working side-by-side in harmony.
A word boundary character '\b' helps you search for the words that begins and/or ends with a pattern. For example, the regexp /\bcar/ matches the words beginning with the pattern car (with 'b' signifies as the 'beginning'), and would match cart, carrot, or cartoon, but would not match oscar.
Similarly, the regexp /car\b/ matches the words ending with the pattern car, and would match scar, oscar, or supercar, but would not match cart.
Likewise, the /\bcar\b/ matches the words beginning and ending with the pattern car, and would match only the word car.
The following example will highlight the words beginning with car in bold:
<?php
/**
* $expression = '/\bcar\w*/';
*
* here, our goal is to match any words beginning with the pattern car (with 'b'
* signifies as the 'beginning').
*
* the expression uses '\' to escape the literal 'b' so that it won't treat 'b'
* as an ordinary character to be matched by the character tokens.
*
* now 'b' becomes a live function to search for words that begin with 'car'.
*
* likewise, we're escaping the 'w' as well so that we can match any word character
* (definned as a to z, A to Z, 0 to 9, and the underscore). Same as [a-zA-Z_0-9].
*
* the 'w' stands for 'words' character as in car, cart, carrot, web, newspaper, etc.
*
* now the '*' is used to match zero or more occurrences of words like:
* car, cart, carrot, web, newspaper, etc.
*
* anytime there is a matched, i.e., 'car', preg_replace() performs a replace of the
* content (car) only after it has been matched using characters contained in
* variable $replacement.
*
* now the characters in $replacement has another special meaning as well.
* it's a buit-in function! see the description below for more.
*
* basically, '$0' acts as a placeholder to hold the matched word.
* so whenever there is a matched, it puts the matched word in $0.
* and then that $0 is replacing the original word in the document making the
* original word(s) bold.
*/
$expression = '/\bcar\w*/';
// '$0' will be replaced by the $string captured by $expression: car, cart, cartoon, etc.
$replacement = '$0';
$string = 'Words begining with car: cart, carrot, cartoon.
Words ending with car: scar, oscar, supercar.';
// preg_replace() performs a replace of the content only after it has been matched
echo preg_replace($expression, $replacement, $string);
/**
* as you can see, there is two parts in this: first, it does the regular expression
* search and match, and second, it uses preg_replace() to just replace the entire old
* strings contain in $expression and replace it with the newly decorated strings in
* $replacement and puts the entirely strings including the newly decorated strings
* back in variable $string ready to be used/displayed.
* preg_replace() just performs a replace of the content only--and no search and match.
*
* output:
* Words begining with car: cart, carrot, cartoon.
* Words ending with car: scar, oscar, supercar.
*/
?>
\\n or $nNotice that variable $replacement may contain references of the form \\n or $n, with the latter form being the preferred one [see $replacement = '$0' above]. Every such reference will be replaced by the text captured by the n'th parenthesized pattern ($expression, in this case). n can be from 0 to 99, and \\0 or $0 refers to the text matched by the whole pattern.
Now a side note: what does it mean: n'th parenthesized pattern?
Well, regular expressions can be very complex and to match all kinds of scenarios some regular expressions need to use parenthesese to group all their many possible expression options. For more check this out parenthesized pattern or this parenthesized pattern.
Opening parentheses are counted from left to right (starting from 1) to obtain the number of the capturing subpattern. To use backslash in $replacement, it must be doubled ("\\\\" PHP string).
When working with a replacement pattern where a backreference is immediately followed by another number (i.e.: placing a literal number immediately after a matched pattern), you cannot use the familiar \\1 notation for your backreference.
\\11, for example, would confuse preg_replace() since it does not know whether you want the \\1 backreference followed by a literal 1, or the \\11 backreference followed by nothing.
In this case the solution is to use ${1}1. This creates an isolated $1 backreference, leaving the 1 as a literal.
{} SyntaxThis isn't called complex because the syntax is complex, but because it allows for the use of complex expressions.
Any scalar variable, array element or object property with a string representation can be included via this syntax. In other words, you can include almost just about anything inside the curely brackets {}. Simply write the expression the same way as it would appear outside the string, and then wrap it in { and }.
Since { cannot be escaped, this syntax will only be recognized when the $ immediately follows the {.
For example, use {\$ to get a literal {$. Notice the curly bracket { and the $ in combination.
Some examples to make it clear:
<?php
// Show all errors
error_reporting(E_ALL);
$great = 'fantastic';
// Won't work, outputs: This is { fantastic}
echo "This is { $great}"; // notice the space gap after {
// Works, outputs: This is fantastic
echo "This is {$great}";
// Works
echo "This square is {$square->width}00 centimeters broad.";
// Works, quoted array keys 'key' only work using the curly brace syntax
echo "This works: {$arr['key']}";
// Works
echo "This works: {$arr[4][3]}";
/**
* This is wrong for the same reason as $foo[bar] is wrong outside a string.
* In other words, it will still work, but only because PHP first looks for a
* constant named foo; an error of level E_NOTICE (undefined constant) will be
* thrown.
*/
echo "This is wrong: {$arr[foo][3]}";
/**
* Works. When using multi-dimensional arrays, always use braces around arrays
* when inside of strings
*/
echo "This works: {$arr['foo'][3]}";
// Works.
echo "This works: " . $arr['foo'][3];
echo "This works too: {$obj->values[3]->name}";
// if $name = 'John Doe' then {${$name}}: 'John Doe'
echo "This is the value of the var named $name: {${$name}}"; // $name: John Doe
// if getName() = 'Jane Doe' then {${getName()}}: 'Jane Doe'
echo "This is the value of the var named by the return value of
getName(): {${getName()}}";
// if $object->getName() = 'Joe Sixpack' then {${$object->getName()}}: 'Joe Sixpack'
echo "This is the value of the var named by the return value of
\$object->getName(): {${$object->getName()}}";
/**
* Won't work, outputs: This is the return value of getName(): {getName()}
* getName() needs an object reference, i.e., $this->getName()
*/
echo "This is the return value of getName(): {getName()}";
?>
It is also possible to access class properties using variables within strings using this curely brackets {} syntax.
<?php
class foo
{
public $bar = 'I am bar.';
}
$foo = new foo();
$bar = 'bar';
$baz = array('foo', 'bar', 'baz', 'quux');
/**
* output: 'I am bar.'
* notice that it's not $foo->bar, but rather, first $foo->$bar, and then $foo->bar
*/
echo "{$foo->$bar}\n";
/**
* first, it executes the inner most code: $baz[1] = 'bar'
* then, it executes the class foo object property: $foo->bar = 'I am bar.'
*/
echo "{$foo->{$baz[1]}}\n";
?>
The above example will output:
I am bar.
I am bar.
Note:
Functions, method calls, static class variables, and class constants inside {$} work since PHP 5. However, the value accessed will be interpreted as the name of a variable in the scope in which the string is defined. Using single (pair) curly braces {} will not work for accessing the return values of functions or methods or the values of class constants or static class variables.
<?php
// Show all errors.
error_reporting(E_ALL);
class beers
{
const softdrink = 'rootbeer';
public static $ale = 'ipa';
}
$rootbeer = 'A & W';
$ipa = 'Alexander Keith\'s';
// This works; outputs: I'd like an A & W. Notice the use of two pairs of {}
echo "I'd like an {${beers::softdrink}}\n";
// This works too; outputs: I'd like an Alexander Keith's. Uses two pairs of {}
echo "I'd like an {${beers::$ale}}\n";
?>
Characters within strings may be accessed and modified by specifying the zero-based offset of the desired character after the string using square array brackets, as in $str[42]. Think of a string as an array of characters for this purpose. The functions substr() and substr_replace() can be used when you want to extract or replace more than 1 character.
Note: As of PHP 7.1.0, negative string offsets are also supported. These specify the offset from the end of the string. Formerly, negative offsets emitted E_NOTICE for reading (yielding an empty string) and E_WARNING for writing (leaving the string untouched).
Note: Strings may also be accessed using braces, as in $str{42}, for the same purpose.
Warning
Writing to an out of range offset pads the string with spaces. Non-integer types are converted to integer. Illegal offset type emits E_WARNING. Only the first character of an assigned string is used. As of PHP 7.1.0, assigning an empty string throws a fatal error. Formerly, it assigned a NULL byte.
Warning
Internally, PHP strings are byte arrays. As a result, accessing or modifying a string using array brackets is not multi-byte safe, and should only be done with strings that are in a single-byte encoding such as ISO-8859-1. Note: As of PHP 7.1.0, applying the empty index operator on an empty string throws a fatal error. Formerly, the empty string was silently converted to an array.
Some string examples:
<?php
// Get the first character of a string
$str = 'This is a test.';
$first = $str[0];
// Get the third character of a string
$third = $str[2];
// Get the last character of a string.
$str = 'This is still a test.';
$last = $str[strlen($str)-1];
// Modify the last character of a string
$str = 'Look at the sea';
$str[strlen($str)-1] = 'e';
?>
String offsets have to either be integers or integer-like strings, otherwise a warning will be thrown. Previously an offset like "foo" was silently cast to 0.
Differences between PHP 5.3 and PHP 5.4
<?php
$str = 'abc';
var_dump($str['1']);
var_dump(isset($str['1']));
var_dump($str['1.0']);
var_dump(isset($str['1.0']));
var_dump($str['x']);
var_dump(isset($str['x']));
var_dump($str['1x']);
var_dump(isset($str['1x']));
?>
Output of the above example in PHP 5.3:
<?php
string(1) "b"
bool(true)
string(1) "b"
bool(true)
string(1) "a"
bool(true)
string(1) "b"
bool(true)
Output of the above example in PHP 5.4:
string(1) "b"
bool(true)
Warning: Illegal string offset '1.0' in /tmp/t.php on line 7
string(1) "b"
bool(false)
Warning: Illegal string offset 'x' in /tmp/t.php on line 9
string(1) "a"
bool(false)
string(1) "b"
bool(false)
?>
Note:
Accessing variables of other types (not including arrays or objects implementing the appropriate interfaces) using {} or {} silently returns NULL.
First of all, in my honest opinion, JavaScript is the most complex language of all the languages out there. The next most complex language is Java. I'm definitely sure that a lot of programmers out there would agree with me on these two languages. However, these two languages are very powerful as well. If you're an expert on these two languages, you're among the high echelon of programmers out there -- espcially if you're a JavaScript guru.
JavaScript is a very powerful language and as such it is very complex as well. In JavaScript, you can have nested functions: functions inside another function and functions inside that function. So there are several levels of nested functions, one nested inside another, making it a spageti-type of intertwine looking code.
Then there is a concept called prototype. What is a JavaScript prototype?
A prototype in JavaScript is an object property variable or a function name object (or the other way around: object function name).
What the heck is function name object (or object function name)?
When you create a function in JavaScript, you create an object by way of the JavaScript engine, which adds a property called prototype to the function. Well, you created a function, which is an object and behind the scene a property called prototype is added to this object you'd just created -- hence the prototype object.
What is an object? To answer that, please see my other tutorial called Class verses Object.
So prototype is inherited from parent class called Object.
This prototype property is an object, which has a constructor property by default. The constructor property points back to the function you'd just created. Did you understand all that? If you don't, it's not the end of the world. Yes, this is advanced JavaScript.
Just know this: When you create a class (or object), you don't have to create properties in that class. Yes, that is right: you don't need to create all properties all at once at the time you create your class; you can create them later on using prototype property object. This feature comes in handy when you decided that you need properties or methods later on.
For example, if you create a class called Car and you forgot to create a property called color, no worries: You can actually create that property called color later outside of that class Car by referring to that class Car like this:
Car.prototype.color = 'blue';
// Now a property called color has been created somewhere
// outside of that class.
Now you can access that property called color just like any other properties as if you had declared it in the class Car in the first place.
Likewise, you create (or declare) a function name after you'd created a class Car and can be done by just specifying the prototype with a function name or more correctly function property: myMethod. For example:
Car.prototype.myMethod = function()
{
return this.color; // blue
};
A prototype in Javascript is an empty object that contains nothing in it. It is just an empty hallowed object that allows you to add properties and methods to an existing object that you already created (i.e., Car class). You can add properties and methods to the object of the class Car.
So a Javascript prototype is a special object similar to PHP's stdClass that allows you to declare variable properties and methods outside of the class definition.
In PHP, you can create an instance of an "all-purpose" class called stdClass and then declare (or add) properties and assign values to those properties.
So stdClass is an "all-purpose" class that contains nothing - no properties or methods - and when you instantiate it, it is an empty object that allows you to basically add properties (or methods, although rare) and assign values to them and use them on the spot.
This is a very convenient "all-purpose" class to use when you need an empty object to hold your properties and use them on the spot.
In PHP, you can do like this:
$customer = new \stdClass(); // notice the use of the namespace directory "\"
$customer->name = 'John Doe';
$customer->address = '123 Main St';
$customer->email = 'john@doe.com';
// now $customer is an object that contains John Doe's information
// now you can do whatever you want with this object $customer
Customer.prototype.name = 'John Doe'; // a property called 'name'
Customer.prototype.getName =
function(
{
return this.name; // 'John Doe'
});
Throw an anonymous function into the mix as well, then you have a language that is very hard to master all of its nooks and crannies.
Immediately-Invoked Function Expression is one of those nooks and crannies. I'm not sure if I understand it very well but I will try to explain it the best I possibly can.
Immediately-Invoked Function Expression (IIFE) is sometimes known as "self-executing function" or "self-executing anonymous function" or "self-invoked function" or "self-invoked anonymous function". They all mean the same thing, and they are all being used interchangibly.
So what exactly is IIFE?
As the expression implies, IIFE, is a self-invoked function -- it is automatically invoked by the browser once the browser encounters the function.
Normally, you have to call the function in order for the function to start executing. In an IIFE function, you just create the function and when the browser encounters the function, it executes the function automatically. Let's see some examples.
IIFE functions:
// there are two versions that you can use
// first version
(function() // <---- the outer "(" marked as the opening of the main function -- start of the main IIFE function
{
// notice that function() is just an ordinary javascript anonymous function that you can put your code in it
// and inside here is its body of that ordinary javascript function and not
// part of the IIFE, but it will be executed by IIFE automatically via chains of reaction
// you can put your code in here!
// more code here!
// .....
}
() // self-invoked function's opening and closing parenthesese
// and typically contains the word "jquery" inside it, i.e., (jQuery)
); // <---- marked as the closing of the main function -- end of the body of IIFE function
// any code between the opening/closing of the "main" function above will be executed by
// the self-invoked function designated by the two parenthese: () and typically contains the word "jquery" inside it
// now the second version
// this version is very popular among slider programmers, particularly jQuery sliders
(function() // <---- the outer "(" marked as the opening of the main function -- start of the IIFE function
{
// notice that function() is just an ordinary javascript anonymous function that you can put your code in it
// and inside here is its body of that ordinary javascript function and not
// part of the IIFE, but it will be executed by IIFE automatically via chains of reaction
// you can put your code in here!
// more code here!
// .....
}
) // <---- marked as the closing of the main body function -- end of the IIFE function
(); // <---- notice that the second version is outside of the main body
// <---- noitce also the ending with a ";" to end the IIFE
// any code between the opening/closing of the "main" function will be executed by
// the self-invoked function above designated by the two parenthese: ()
// and typically contains the word "jquery" inside it, i.e., (jQuery)
Question: How many of you Javascript programmers out there have seen or programmed using the above two syntaxes? If you have -- great! If not, it's not the end of the world! This is advanced Javascript programming.
That is it!
This is Immediately-Invoked Function Expression.
Now name each function version above into its own file name and navigate your broswer to the location you stored the files and you'll see some sort of results that the browser will output. Just put some content meaningful in the functions, such as an alert() or a console.log() for the browser to output some content.
As you can see, in the first version, IIFE function starts out with an opening parenthesis "(" and ends with a closing parenthesis ")"; while the second version is the same as the first version except that it pulls out the invoked-function's opening parenthesis "(" and the invoked-function's closing parenthesis ")" out of the enclosing parenthesese "()" and puts them outside of the main body at the very end of the function.
The invoked-function's opening parenthesis "(" and the invoked-function's closing parenthesis ")" invoke the function enclosed inside the outer parenthesese. In other words, "()" invokes the main function (main body) which is enclosed between the outer opening parenthesis "(" and the closing parenthesis ")".
That is all to know about Immediately-Invoked Function Expression. The rest is up to you to come up with logic inside the function to perform your objective. Here is a very brief example to help you get some ideas to get you heading in the right direction.
// it is customarily to place a semicolon ";" at the beginning of every
// self-invoked function
// this is to prevent bugs that might have been carried forward from
// other functions.
// so putting a semicolon ";" at the beginning of every self-invoked function
// delimits prior code from the previous functions that
// might have carried forward.
;(function(d)
{
var b = {
BigImagePath : "Content/mediafile/",
BigImageBorderColor : "FFF"
};
function i(j)
{
var k = "";
if (j != null)
{
// lastIndexOf returns the position of the last occurrence of a
// specified value (/) in a string (j)
if (j.lastIndexOf("/") == -1)
{
k = j
}
else
{
// + 1 to account for the starting position at 0
k = j.substring(j.lastIndexOf("/") + 1)
}
}
return k
}
a = {
start : function()
{
d(e).mousemove(function(k)
{
// some code logic
}
return d(e);
} // end start = function()
}; // end function a
/**
* remember "prototype" ?
*
* a prototype in JavaScript is an array property variable object.
* when a function is created in JavaScript, the JavaScript engine adds an array
* variable prototype property to the function.
* this array variable prototype property is an object (called prototype object)
* which has a constructor property by default.
* the constructor property points back to the function on which prototype object
* is a property.
*
* here (below), we create a function named mySlide and the JavaScript engine
* adds an array variable prototype property to this function mySlide.
* the default constructor property points back to this function mySlide.
* so in a sense, mySlide has a default constructor which is automatically called
* whenever this function is invoked or executed.
*
* to call/execute this function, do like this using jQuery statement:
* $("img.element_by_id_of_image_being_pointing_to").mySlide(setting);
* argument variable setting is passed to argument variable j
*/
d.fn.mySlide = function(j)
{
e = this;
if (a[j])
{
return a[j].apply(this, Array.prototype.slice.call(argument, 1))
}
else
{
if (typeof j === "object")
{
d.extend(b, j);
return a.start.apply(argument)
}
else
{
if (!j)
{
return a.start.apply(this, argument)
}
else
{
d.error("Method " + j + " does not exist on jQuery.mySlide")
}
}
} // end else
} // end d.fn.mySlide = function()
} // end function(d)
) // end main function()
(jQuery); // end self-invoked function()
Don't try to run this function because it is incomplete; it is an abbreviated listing of the actual functional jQuery slider that I wrote for my homemade project. This is just an illustration to help you understand the concept of Immediately-Invoked Function Expression.
Just like an Immediately-Invoked Function Expression (or IIFE) in Javascript, a PHP Immediately-Invoked Function Expression (or IIFE) is also known as a "self-executing function" or "self-executing anonymous function" or "self-invoked function" or "self-invoked anonymous function". They all mean the same thing, and they are all being used interchangibly.
As a matter of fact, the Immediately-Invoked Function Expression (or IIFE) in PHP is a copycat of the Javascript counterpart. So if you understand the Javascript Immediately-Invoked Function Expression (or IIFE), you should have no trouble understanding PHP Immediately-Invoked Function Expression (or IIFE) because it adopted the functionality of the Javascript's IIFE. IIFE is only available in PHP version 7 or later.
/**
* as stated earlier, PHP version of IIFE is a copycat of Javascript IIFE
* so semantically and syntactically both PHP and Javascript versions are the same
* the below definition is all you need to know, and the rest is up to you to come
* up with the actual code logic that suite your objective!
*/
<?php
echo (function() // <---- the outer "(" marked as the opening of the main function -- start of the main IIFE function
{
// notice that function() is just an ordinary PHP anonymous function that you can put your code in it
// and inside here is its body of that ordinary PHP anonymous function and not
// part of the IIFE, but it will be executed by IIFE automatically via chains of reaction
// you can put your code in here!
// more code here!
// .....
return 12; // will output 12
}
) // <---- marked as the closing of the main body function -- end of the IIFE function
(); // <---- self-invoked function's opening and closing parenthesese
// notice that this is exactly as Javascript's IIFE second version: appearing outside of the body
// notice also the ending with a ";" to end the IIFE
?>
<?php
$foo = (function()
{
return function($a)
{
return $a + 15;
};
}
)(); // <---- notice the ending with a ";" to end the IIFE
?>
Usage:
echo $foo(10); // will output 25
/**
* Note that in this example, when accessing an outer variable ($a) from within a function,
* function($b) in this case, we - unlike in JavaScript which has closures - need to use
* the use keyword to make that variable accessible: use ($a)
*/
<?php
$foo = (function($a)
{
// notice the nested anonymous functions, first, returning the innermost function
// and second, returning the next outer nested function
return function($b) use ($a)
{
return $a + $b;
};
}
)(15); // <---- notice that you can put some code inside the IIFE: 15 in this case
?>
Usage:
echo $foo(10); // will output 25
There you have it!!!
Note that this is just a very brief introduction to Delphi.
For more Delphi tutorials, please Google the subject and you'll get lots of resources to get you started.
Note that in Delphi, the syntax is slightly different than with other languages, for example, in other languages you use curly braces or brackets '{}' to group your block of code, such as the beginning and ending of a block of code. For example:
In other languages:
class MyClass
{
public function aMethod()
{
// code blocks
var number, zero;
if (true)
{
// if true code block
}
else if (...)
{
// else if code block
}
else
{
// else code block
}
try
{
zero := 0;
number := 1 div zero;
alert('number / zero = ' + number.toString());
}
catch (Exception e)
{
e.message('Unknown error encountered');
}
} // end function aMethod()
} // end class MyClass
In Delphi:
Type
TMyClass = class
public
class function aMethod()
begin // begin function aMethod block
// inside function aMethod code blocks
var
number, zero : Integer;
if (true) then
begin
// true condition code block
end // end if (true) then condition block without a ";"
else if (...) then
begin
// else if condition code block
end // end "else if" (...) block without a ";"
else
begin
// else condition code block
end // end "else" block, and it can contain a ";" as well -- it's optional!
end; // notice the "end" and a ";" to end the whole "if/else if/else" blocks!
// the ";" after thd "end" is a must and not an optional!
// Try to divide an integer by zero - to raise an exception
try
zero := 0;
number := 1 div zero;
ShowMessage('number / zero = ' + IntToStr(number));
except
ShowMessage('Unknown error encountered');
end; // end try block and it must contain a ";" -- it's not an optional!
end; // end function aMethod() - the ";" after the "end" is a must and not an optional!
end; // end class TMyClass block - the ";" after the "end" is a must and not an optional!
// Notice that in Delphi it uses keywords 'begin' and 'end',
// in certain blocks it can followed by a semicolon ';', to seperate between blocks.
// Note also that in a main program (not shown here) the final 'end' should be a period '.' instead of
// a ';' to end the whole program.
As you can see, once you know the basic syntax everything is trivial, especially if you're coming from other languages. All programming languages basically are identical in concept and foundation; for example, all languages have classes and all classes have three types of attributes.
Delphi also has three types of attributes: 1st type of attributes, 2nd type of attributes, 3rd type of attributes.
To learn more about the three types of attributes, please see my other tutorial called Class verses Object on this website.
Knowing that, let's start with a class definition and some basic language constructs like comment tags and letter casing.
Make note that in Delphi, an embedded comment is between the curly braces: {}. In other languages, they are: //, /* .... */.
// Delphi is a case-insensitive language, meaning upper- and lower-case letters are treated
// as lower-case letters -- indiferenced.
// this is a single-line comment in other languages such as PHP, Java, C/C++, Javascript, etc.
/* this is a multi-line comment in other languages such as PHP, Java, C/C++, Javascript, etc. */
// In Delphi, this is a single-line comment
{ In Delphi, this is a multi-line comment }
// In Delphi, the declaration section must begin with a "Type" keyword
Type
{ All class definitions must follow the "Type" heading }
{ The definition of a class must begin with the reserved keyword class. For example: }
// In Delphi, it is customarily to put a 'T' (for "Type") at the beginning of the class name
TMyClass = class // start of the class TMyClass declaration section
// 1st type attributes:
// In Delphi, this is how you declare your properties
{ As with other languages, Delphi has visibility controls also: public, protected, private }
public // begin a 'public' visibility control declaration section
const Max = 100; // declares a constant called Max that holds the integer 100
// If the right side of the equal sign returns an ordinal value, you can specify
// the type of the declared constant using a value typecast. For example:
const Number = Int64(20); // declares a constant called Number, of type Int64, that holds the integer 20
// To declare an array constant, enclose the values of the elements of the array,
// separated by commas, in parentheses at the end of the declaration.
// These values must be represented by constant expressions. For example:
// In PHP: const Digit = array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9');
// Or: const Digit = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
const Digit: array[0..9] of Char = ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9');
// Above constant declaration: declares a typed constant called Digit that holds an array of characters 0 to 9
// The constant variable Digit can be accessed as an array as you normally would (in other languages) like this:
// Digit[0] ----> will hold a constant character string value of '0'
// Digit[1] ----> will hold a constant character string value of '1'
// Digit[2] ----> will hold a constant character string value of '2'
// Digit[3] ----> will hold a constant character string value of '3'
// and so on up to 9
// Notice that they hold character values (i.e., '0', '1', '9') and not integer values.
// But the array indexes are integer values (i.e., 0, 1, 2) as a normal array index.
// To declare a constant variable containing integer values, do the following:
const Digit: array[0..9] of Integer = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
// Above constant declaration: declares a typed constant called Digit that holds an array of integers 0 to 9
// Similarly the variable Digit can be accessed as an array like the above characters example
// Simialrly you can declare a constant without the definition values as well:
const Digit: array[100..200] of Integer;
// And then in the implementation section you can assign values like the following:
Digit = array(100, 101, 102, 103, 104, 105, 106, 107, 108, 109, ...);
// The following declares a string typed constant called Day that holds an array of strings
const Day: array[0..6] of String = ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat');
// The constant string variable Day can be accessed as an array as you normally would like this:
// Day[0] ----> will hold a constant string value of 'Sun'
// Day[1] ----> will hold a constant string value of 'Mon'
// Day[2] ----> will hold a constant string value of 'Tue'
// Day[3] ----> will hold a constant string value of 'Wed'
// and so on up to 'Sat'
{ The purpose of the 1st type of attributes of the class (above) is to store content values that }
{ are constant and can't change its values during the lifecycle of the application }
// 2nd type attributes:
{ a property called 'A' is declared as 'public'
to access this property call getA(), to set this property call setA(10)
you normally call this property from anywhere inside the class, particularly from
inside the constructor using the global variable 'self' which is equivalent to $this in PHP:
self.setA(10); // property A is now holds an integer 10
A = self.getA(); // A = 10
}
{
notice that you can name the getter/setter (i.e., getA(), setA(), etc.) with any name you wish,
but the convention is to use camelCase, i.e., getMyPropertyA(), setMyPropertyA()
and as well as leaving out the () from the getter/setter methods as shown in the following:
}
class property A : Integer read getA write setA;
{ a property called 'B' is declared as 'public' }
to access this property call getB(), to set this property call setB(10) }
class property B : Integer read getB write setB;
protected { begin a 'protected' visibility control declaration section }
// likewise, to access this property call getX(), to set this property call setX(10)
class property X : Integer read getX write setX;
private // begin a 'private' visibility control declaration section
{ likewise, to access this property call getY(), to set this property call setY(10) }
class property Y : Integer read getY write setY;
// As you can see above, these property values can and will change their
// values during the lifecycle of the application
// As with other languages, Delphi has a 'var' type for declaring variables
var
number, zero : Integer;
myChar : Char;
myDateFormat : String;
isCorrect : Boolean;
// So the purpose of the 2nd type of attributes of the class (above) is to store content
// values that are constantly changing (its values) during the lifecycle of the application
{ In Delphi, this is how you declare your static methods }
// 3rd type attributes:
public // begin a 'public' visibility control declaration section
class function StatFunc(s : String); static; { a static function method }
class procedure StatProc(s : String); static; { a static procedure method }
class function Add(A : Integer, B : Integer) : Integer; { a regular, 'non-static', method }
class function GetCount(); { a regular, 'non-static', method }
protected { begin a 'protected' visibility control declaration section }
{ a regular, 'non-static', method }
class function Method1();
private // begin a 'private' visibility control declaration section
{ a regular, 'non-static', method }
class function Method2( { just like other languages you can embedd multi-line comment as well } );
{ In Delphi, this is how you declare your constructor method }
{ In Delphi, you have to declare your constructor method using a function/constructor name called
{ Create() with the same format as shown here}
public { a constructor and a destructor are declared as a 'public' visibility control }
// see a similar constructor method implementation later in the TShape example
constructor Create(Owner : TComponent); override;
{
As you may know already, a constructor gets called by other code very frequently, and as such,
it uses a lot of internal chipset registers. registers are like blackboards to write on.
in a blackboard, you need to erase the blackboard when the materials on it are not needed.
similarly in computer programming, you need to reclaim the used registers so that you can
use them again.
}
{
Delphi is a low-level language that can operate on chipset registers much like assembly
language can; and therefore, it can reclaim registers used during operations.
this destructor does that by reclaiming the used registers and clean out the garbages created
by the constructor.
}
destructor Destroy; override;
{ The purpose of the 3rd type of attributes of the class (above) is to calculate and manipulate }
{ the content values that contain in the 1st and 2nd types of attribute property variables }
end; { end of the class TMyClass declaration section }
{ Notice that after the end of the class TMyClass declaration section you can
declare another class declaration section as well, i.e., TMyOtherClass,
using the same format as above.
This is called "stacking" -- we're stacking classes one on top of another.
You can do this with other languages as well and it works the same way for the same purpose.
What it does is that, instead of having to create a seperate file for each class, you can
stack them on top of one another in the same file and call them from any class, and from
anywhere using only one include file statement, and saving you the effort of having to include
all of the files.
However, this practice of "stacking" is discouraged in all medium to large applications because
it can get cluttered and hard to debug.
So in most every day programming chores, "stacking" is discouraged and only in certain
situations where less cluttered can be achieved that you should use "stacking".
Having said that, here is how you can stack your classes:
}
TShape = class(TGraphicControl)
private
FPen : TPen;
FBrush : TBrush;
procedure PenChanged(Sender : TObject);
procedure BrushChanged(Sender : TObject);
public
{ This is a Delphi constructor: Constructor T{your_class_name}.Create()
In PHP: function __construct() }
constructor Create(Owner : TComponent); override;
destructor Destroy; { just like other languages you can embedd multi-line comment as well } override;
{ ... more code here! }
end; { end of the class TShape declaration section }
{ begin the constructor implementation section }
constructor TShape.Create(Owner : TComponent);
begin
inherited Create(Owner); // Note: this is a single-line comment: Initialize inherited parts
Width := 65; { Note: this is a multi-line comment: Change inherited properties }
Height := 65;
FPen := TPen.Create; // Initialize new fields
FPen.OnChange := PenChanged;
FBrush { just like other languages you can embedd multi-line comment as well } := TBrush.Create;
FBrush.OnChange := BrushChanged;
// Assuming you had declared these property methods like shown earlier, you can call them:
self.setA(10); // In PHP: $this->A = 10;
A = self.getA();// In PHP: $A = $this->A;
end;
As you can see, it is very easy to program in Delphi and it is also a very powerful language that can work with very low level registers similar to Assembler language.
For more resources on the subject of Delphi programming language, here is a link to the Delphi
Delphi is a programming language for the desktop applications and for cross-platform mobile applications such as building apps for smartphones (i.e., iOS and Android platforms) using Delphi. Here is a link to an excellent tutorial titled: Building your first Native Mobile Applications for iOS and Android Building Cross-Platform Mobile Applications Using Delphi: Building a REST Client for Stack Overflow
Typically, you would need to find an iOS platform SDK to build your iPhone mobile applications that can run on an iOS platform and then you would need to find an Android platform SDK to build your mobile applications that can run on Android platform.
With Delphi mobile platform, you can build both iOS and Android mobile applications using only one SDK platform. This is very convenient and powerful and not to mention the simpicity of having to learn only one platform for building cross-platform mobile applications.
Again, if you are interested into the deep end of the programming language world for both desktop and mobile, start with the free and full-featured Community Editions of Delphi and C++Builder. Community Editions of Delphi and C++Builder are designed to help you get started programming. These powerful IDEs provide all the features you need to quickly explore robust app development.
When Community Edition launched it made all the features of the Professional Edition of Delphi and C++Builder free to students and hobbyists in the community: including mobile platforms, desktop database, and the full source code for the runtime libraries. Now the 10.4.2 Sydney update brings the absolutely latest features and updated platform support to Delphi & C++Builder Community Edition.
There's no better way to build powerful native applications for iOS, Android, Windows, and macOS from a single codebase than using the robust and easy-to-learn Delphi language. This makes it the ideal choice for students or anyone who just wants to get things done.
C++Builder is your choice if you want to master the mysteries of the curly brace (see illustration below). It unlocks a huge variety of C++ standard libraries, while still giving you access to the powerful runtime libraries included in Delphi. This is a winning combination for C++ development.
The Community Editions of Delphi & C++Builder are designed for students and hobbyists. If that is you, and you are new to programming, then download the free Community Edition of your choice [Delphi 10.4.2 CE or C++Builder 10.4.2 CE] and register for the free Learn to Code Summer Camp.
Community Editions are available free of charge to developers, and organizations with fewer than five developers. Here are the download links Start Learning Delphi for Free: Delphi & C++Builder FREE Community Editions Start Learning Delphi for Free: Download the FREE Delphi Community Edition Start Learning Delphi for Free: Download the Free C++Builder Community Edition
Here is an introduction to Model-View-View Model (MVVM) in Delphi:
An Introduction to Model-View-View Model (MVVM) in Delphi: Build an MVVM App in Twenty Minutes An Introduction to Model-View-View Model (MVVM) in DelphiFor more resources on the subject of Delphi programming language, here are some links to the Delphi resources:
Delphi Community Development Forum Delphi BlogsThis code is an example of how to create a form and a button in a Delphi application.
The goal is to create a new form and a new button when a user clicks on a button in a Delphi application.
This code has a form (TForm1) with a single button.
Each time a user clicks on a button, a new button and a new form are created on the fly.
The created button is shown on the TForm1.
The form TForm1 is created but not visibly shown.
A list (FList) keeps a reference to the created button and form.
The created button and form have their Tag property set to the index in the list.
The button's OnClick event handler uses this index to retrieve the corresponding form from the list and make it visible.
In other words, when a user clicks on the button shown on the form it executes the Button1Click() procedure, and inside this procedure that it fires up an OnClick event property causing the private procedure MyClick() to be called.
The form is created with a nil Parent so that it is a flying window.
If you use self instead of nil, the created form will be inside the TForm1, much like a DMI application.
File: FormButtonApp.pas
{ Each Delphi application is a unit}
{ A typical Delphi application starts with a unit keyword follows by a name, and in this example
it is called "DynFormDemo"}
Unit DynFormDemo; // name of the unit of this application
{ Each Delphi application contains an interface section}
Interface { An interface section is like a declaration section}
{ Each Delphi application contains a "uses" clause (or include statement in PHP)}
{ The "uses" clause lists all the units/libraries that this unit uses}
Uses Winapi.Windows, Winapi.Messages, System.SysUtils, Sysyem.Variants,
System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCntrls,
System.Generics;
{ You declare all your classes and records and all other declarations in the type section}
Type
TFormItem = record
AForm : TForm;
AButton : TButton;
end; { An end of a record declaration section}
TForm1 = class(TForm);
{ Any declaration without specific visibility/access control fall under public section}
Button1 : TButton;
{declaring a button procedure for a user to click}
procedure Button1Click(Sender : TObject);
private
FList : TList <TFormItem>;
procedure MyClick(Sender : TObject);
public
constructor Create(AOwner : TComponent); override;
destructor Destroy; override;
end;
Var
Form1 : TForm1; {yes, TForm1}
{ Each Delphi application contains an implementation section where you implement the
actual code contain in the interface section}
implementation
{$R *.dfm}
{implement a button procedure for a user to click}
procedure TForm1.Button1Click(Sender : TObject);
var
Item : TFormItem;
AButton : TButton;
AForm : TForm;
begin
{create an instance of the TButton object}
{this is how you create a button}
AButton := TButton.Create(Self);
{setting the properties of the button}
AButton.Tag := FList.Count;
AButton.Left := 80;
AButton.Top := 50 + AButton.Tag * 60;
AButton.Width := 300;
AButton.Height := 50;
AButton.Name := 'Liste' + IntToStr(AButton.Tag);
AButton.Caption := ClassName + ' ' + IntToStr(AButton.Tag);
AButton.OnClick := MyClick; {tying a button to a procedure to execute}
AButton.Parent := Self;
{create an instance of the TForm object}
{this is how you create a form}
AForm := TForm.Create(Self);
{setting the properties of the form}
AForm.Tag := AButton.Tag;
AForm.Left := AButton.Tag * 20;
AForm.Top := AButton.Tag * 20;
AForm.Width := 200;
AForm.Height := 100;
AForm.Name := 'John Doe' + IntToStr(AForm.Tag);
AForm.Caption := 'John Doe' + IntToStr(AForm.Tag);
AForm.Parent := nil;
AForm.Visible := FALSE;
Item.AForm := AForm;
Item.AButton := AButton;
FList.Add(Item); {adding a form containing a button to the list}
end;
constructor TForm.Create(AOwner : TComponent);
begin
inherited;
FList := TList <TFormItem>.Create;
end;
destructor Destroy;
begin
FreeAndNil(FList);
inherited;
end;
{when a user clicks on a button the event of the click action is captured and sent via}
{the variable Sender. You can name this variable any name you wish}
{you can use this captured event variable Sender to do whatever necessary [as shown below]}
procedure TForm1.MyClick(Sender : TObject);
var
Item : TFormItem;
begin
Item := TList[(Sender as TButton).Tag]; {tying a button to the list}
if assigned(Item.AForm) then
begin
Item.AForm.Show; {display the form and the button in the list}
end;
end;
end.
Form objects are the basic building blocks of a Delphi application, the actual windows with which a user interacts when they run the application. Forms have their own properties, events, and methods with which you can control their appearance and behavior. A form is actually a Delphi component, but unlike other components, a form doesn't appear on the component palette.
We normally create a form object by starting a new application (File | New Application). This newly created form will be, by default, the application's main form - the first form created at runtime.
Note: To add an additional form to Delphi project, (in the Delphi IDE) select File|New Form.
Make sure you have a Delphi IDE installed on your computer. Check out the Delphi Community Development Forum for guidance.
The OnCreate event is fired when a TForm is first created, that is, only once. The statement responsible for creating the form is in the project's source (if the form is set to be automatically created by the project). When a form is being created and its Visible property is True, the following events occur in the order listed: OnCreate, OnShow, OnActivate, OnPaint.
You should use the OnCreate event handler to do, for example, initialization chores like allocating string lists.
Any objects created in the OnCreate event should be freed by the OnDestroy event.
There may be instances when you do not know the exact class type of a form object. You may only have the string variable carrying the name of the form's class, such as "TMyForm".
Note that the Application.CreateForm() procedure expects a variable of type TFormClass for its first parameter. If you can provide a TFormClass type variable (from a string), you will be able to create a form from its name.
The FindClass() Delphi function locates a class type from a string. The search goes through all registered classes. To register a class, a procedure RegisterClass() can be issued. When the FindClass function returns a TPersistentClass value, cast it to TFormClass, and a new TForm object will be created.
Create a new Delphi project and name the main form: MainForm (TMainForm).
Add three new forms to the project, name them:
FirstForm (TFirstForm)
SecondForm (TSecondForm)
ThirdForm (TThirdForm)
Remove the three new forms from the "Auto-create Forms" list in the Project-Options dialog.
We're working from the Delphi IDE using form designer available in the IDE.
Drop a ListBox on the MainForm and add three strings: 'TFirstForm', 'TSecondForm', and 'TThirdForm'.
procedure TMainForm.FormCreate( Sender: TObject);
begin
RegisterClass(TFirstForm);
RegisterClass(TSecondForm);
RegisterClass(TThirdForm);
end;
In the MainForm's OnCreate event register the classes:
procedure TMainForm.CreateFormButtonClick( Sender: TObject);
var s : string;
begin
s := ListBox1.Items[ListBox1.ItemIndex];
CreateFormFromName(s);
end;
Once the button is clicked, find the selected form's type name, and call a custom CreateFormFromName procedure:
procedure CreateFormFromName(const FormName : string);
var fc : TFormClass;
f : TForm;
begin
fc := TFormClass(FindClass(FormName));
f := fc.Create(Application);
f.Show;
end; (* CreateFormFromName *)
If the first item is selected in the list box, the "s" variable will hold the "TFirstForm" string value. The CreateFormFromName will create an instance of the TFirstForm form.
The following code doesn't work because it doesn't start an event loop to keep the process running.
Form window = new Form(); window.FormBorderStyle = FormBorderStyle.None; window.BackgroundImage = blurred; //blurred is a Bitmap window.SetBounds(bounds.X, bounds.Y, bounds.Width, bounds.Height); //bounds is a Rectangle window.Show();
Change the above code to:
Form window = new Form(); window.FormBorderStyle = FormBorderStyle.None; window.BackgroundImage = blurred; //blurred is a Bitmap window.SetBounds(bounds.X, bounds.Y, bounds.Width, bounds.Height); //bounds is a Rectangle Application.Run(window);
The addition of Application.Run starts a message processing loop so that the application is now waiting for events to process until you run Application.Exit.
Sending the window through to this command guarantees that exit is automatically run when you close your form so you don't accidentally leave the process running in the background.
There is no need to run your forms show() method as Application.Run makes this visible for you automatically.
That said I would still recommend using a method similar to what was posted by LarsTech as it solves some additional problems.
static void main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Form window = new Form();
window.StartPosition = FormStartPosition.Manual;
window.FormBorderStyle = FormBorderStyle.None;
window.BackgroundImage = blurred; //blurred is a Bitmap
window.SetBounds(bounds.X, bounds.Y, bounds.Width, bounds.Height);
Application.Run(window);
}
Application.EnableVisualStyles tells your application to default to the styles used at your OS level.
Application.SetCompatibleTextRenderingDefault has been defaulted to false in new forms projects since Visual Studio 2005. You should have no reason to change it as you are obviously doing new development.
Make sure you have a message pump running.
Something like:
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Form window = new Form();
window.StartPosition = FormStartPosition.Manual;
window.FormBorderStyle = FormBorderStyle.None;
window.BackgroundImage = blurred;
window.SetBounds(bounds.X, bounds.Y, bounds.Width, bounds.Height);
Application.Run(window);
}
The other thing to make sure is that your bounds rectangle is actually within the screen dimensions.
To be continued!!!
In every programming language there is an entry point of execution of the application. In other words, every program or application there is a starting point for the program to begin executing the code.
In Java, that starting point is a function called main().
Note: A function is also known as a method and both can be used interchangibly.
Every Java program or application has to have a main() function to jumpstart the application. If you program a Java program, you'll need to create a function called main(), otherwise, it will give you an error and your Java program won't start.
Java main() method is the entry point of any java program. Its syntax is always like this:
public static void main(String[] arg)
As often the case for any method or function, it is normally belonging to a class and must reside in a class. In the following, we have a class called "HelloWorldApp".
File: HelloWorldApp.java
class HelloWorldApp
{
public static void main(String[] arg)
{
System.out.println("Hello World!"); // Display the string
}
}
Let's continue talking about the function main() in greater details.
The main() method accepts one array string argument, in this case, arg. Notice that arg is of type array String[].
It doesn't have to be named as arg - it can be any name you choose, but it has to be a type 'String[]'.
The array arg contains the values of what the user will type after the class name, when compiling/running or launching your program. For example, to run a class named Foo, the user must type the run command, followed by a compile directive, and in this case, 'java', followed by a class name 'Foo':
$ java Foo
Notice that I specified '$' as a temporary run command symbol. So you'll have to check the Java documentation to find out the exact run command as this tutorial in not about running a Java program but rather it is about a main() method.
Note also that nowaday people don't use run command line any more. The command line like: $ java Foo bar baz is nowaday outdated. Now they are often use IDE (or Integrated Development Environment), a sort of GUI (or Graphic User Interface) development program to do all of their programming work to make their lives easier.
So in this tutorial it is a moot point or useless point in showing you a particular IDE that is not your intended IDE of preference, and therefore, showing an outdated general command line is for an illustration purpose only.
So the message is this: Check out your IDE's instruction on how to compile, run, and use your IDE to do your programming work.
In a NetBean IDE, you can just select your project to open it and once it open, just select 'Run' from the menu bar at the top of the window and it will run your entire project for you.
If you have to run with arguments, say bar and baz, etc., instead of selecting 'Run', just select 'Run with Arguments' and a window opens up for you to enter the argument parameters. In this window, you can select or enter files as arguments as well.
As you may know, at times you may have a file or files for your program to read at run-time, such as a product rating table that contains ratings on each product if you're doing an ecommerce application.
To read the file containing product ratings at run-time, you'll have to include that file in the command line or in most cases nowaday in your IDE command line.
Of course, there are other ways of including files in your program as well and including it at run-time on the command line is one of the ways.
Now remember that this tutorial is about Java method main() and not about IDE or files.
Now everything the user types after the class name ('Foo') is considered to be a parameter. For example:
$ java Foo bar baz
Now when you type a similar command as shown above (provided you use the correct run command or IDE run command), the Java compiler engine reads the command and processes it accordingly.
In the case above, it receives a class Foo and two parameters: bar and baz. These parameters are stored in the array arg contains in the method: public static void main(String[] arg).
In other words, after you type the command it picks out all the various items and place them in the appropriate place, particularly, placing the two string items bar and baz in the string array argument called arg.
Now arg is an array variable containing two elements: arg[0] = 'bar', arg[1] = 'baz'.
Now you can access the first element by accessing arg[0], the second element by accessing arg[1], and so on if you provide more arguments at the command line when you run the command.
If you try to access an invalid position (when you didn't type what you were supposed to type), that statement will throw an ArrayIndexOutOfBoundsException, just like it would with any array. You can check how many parameters were typed with arg.length.
In other words, to find out how many arguments you supply to the command, use arg.length. For example:
public static void main(String[] arg)
{
if (arg.length > 0)
{
// We're checking arg to decide whether it is bar or other:
if (arg[0].equals("bar"))
{
// do something with bar parameter
}
else if (arg[0].equals("other"))
{
// do something with 'other' parameter
}
}
} // end main()
So the number of arguments in main(String[] arg) is dependent on the run-time user input into the command line or IDE GUI. The arguments can be a file or any ordinary variables that you want to pass into the main() function.
A typical usage would be to check if variable arg contains anything by checking the array length, and if it's ok, you access arg[0] to read what a user has typed on the command line. And then, you can process the arguments accordingly. For example:
public class Foo
{
public static void main(String[] arg)
{
if (arg.length == 0)
{
System.out.println("no arguments were given."); // Display the string
}
else
{
for (String a : arg)
{
System.out.println(a); // Display the string in variable 'a'
}
}
}
}
The above class will parse the parameters entered on the command line by a user. If he/she hasn't type anything, the class will print the message "no arguments were given."
If he/she typed something on the command line, those parameters will be shown on the screen.
So, if you run this class with the two examples shown in the following, the output would be shown accordingly, with the first one showing: no arguments were given., and the second one: bar baz.
$ java Foo
no arguments were given.
$ java Foo bar baz
bar
baz
In summary about function main() is that we can pass arguments to the main() method using command line during run-time. For example:
java myjavacode.MyClass Hello World
When the JVM executes the main() method of the myjavacode.MyClass, the String array passed as parameter to the main() method will contain two Strings: "Hello" and "World".
And you can access those values using the string array parameter contained in main(); for example, if you named your parameter as arg, then it would be: arg[0] = 'Hello' and arg[1] = 'World'.
Another typical usage for function main() is to read some files from external sources and then process those files accordingly inside function main(). Let's see an example to illustrate the point.
/**
* Stores a collection of product ratings efficiently in a
* file.
*/
public class MyFileReader implements Serializable
{
// there should be lots of public and private variable declaration here!
private static final long serialVersionUID = 7526472295622776147L;
/**
* Default constructor.
*/
public MyFileReader()
{
// there should be some constructor initialzation code here!
}
/**
* Reads a text file in the form of:
*
* product id, user id, product rating
*
* pid, uid, rating
*
* or something like this:
*
* sku-001, john_doe_123, 4
* sku-002, jane_doe_666, 5
* sku-003, mary_q_public_777, 2
* sku-004, joe_sixpack_999, 3
*
* this function readData() is called by main() below at the bottom
* passing the parameters of main() that the user entered as file names.
* for example:
*
* MyFileReader reader = new MyFileReader();
*
* String sourceFile = null;
* String destFile = null;
*
* the array arg is obtained from: public static void main(String arg[])
*
* notice that you put the "[]" next to 'String' or next to 'arg' and
* it will work just fine!
*
* sourceFile = arg[0];
* destFile = arg[1];
*
* reader.readData(sourceFile);
*/
public void readData(String fileName)
{
try
{
Scanner in = new Scanner(new File(fileName));
String[] line;
short pid;
int uid;
byte rating;
String date;
while (in.hasNextLine())
{
line = in.nextLine().split(",");
pid = Short.parseShort(line[0]);
uid = Integer.parseInt(line[1]);
rating = Byte.parseByte(line[2]);
// these two methods are not included here due to space constraint
addToProduct(pid, uid, rating);
addToCust(pid, uid, rating);
}
}
catch(FileNotFoundException e)
{
System.out.println("Can't find file " + fileName);
e.printStackTrace();
}
catch(IOException e)
{
System.out.println("IO error");
e.printStackTrace();
}
}
// here is the function main() that we're interested in!
public static void main(String arg[])
{
/**
* notice that you put the "[]" next to 'String' or next to 'arg' and
* it will work just fine!
*/
// instantiating our file class
MyFileReader reader = new MyFileReader();
// initialize our two files to be utilized
String sourceFile = null;
String destFile = null;
try
{
/**
* now right here is the crux of our tutorial about main()
* notice that the array arg contains two argumemt parameters
* one has the array element o and another has array element 1.
*/
sourceFile = arg[0];
destFile = arg[1];
// the rest of the code in the following is just ordinary
// file processing code using function readData() to do it!
reader.readData(sourceFile);
reader.sortHashes();
IntArrayList user = reader.custProduct.keys();
for (int i = 0; i < user.size(); i++)
{
System.out.println(user.get(i));
}
serialize(destFile, reader);
}
catch(Exception e)
{
System.out.println("usage: java MyFileReader sourceFile destFile");
e.printStackTrace();
}
} // end void main()
} // end class MyFileReader implements Serializable
There you have it!
A very brief introduction to function main().
For more Java tutorials, please Google the subject and you'll get plenty of resources to get started.
Here is a very good place to get started.
You'll have to follow the Learning Trail by starting from the 'Getting Started' start of the trail and following its 'Trail' to the end of the trail by clicking the 'Next >>' from topic to topic.
If you finish the 'Trail' you'll be an expert in Java:
Introduction to Java: Learning TrailA vararg is a variable-length argument list (a.k.a. vararg, variadic arguments), using the ellipsis (three dots, ...) token before the argument name to indicate that the parameter is variadic, i.e., it is an array variable to hold all parameters supplied by the caller of the function.
It is an arbitrary number of arguments in a method or constructor. It contains a list of arguments in a method, function, or constructor.
A simplier way of saying is that, a vararg is a variable token that accepts an arbitrary number of arguments in a method, function, or constructor.
Let's put it this way: When you create a method, a function, or a constructor, you have to declare your method, function, or constructor with an exact number of arguments, for example: public (a type, i.e., double) MyMethod(a, b, c). Notice that you have three arguments: a, b, c.
Now instead of having to declare an exact number of arguments (3 in the above case), you can use a variable token to declare in your method, function, or constructor to accept an arbitrary unknown number of arguments in your method, function, or constructor. For example: public String MyMethod(...vararg).
Notice an ellipsis (three dots, ...) in front of the variable vararg. This is called a vararg.
You can use a construct called vararg to pass an arbitrary number of values to a method. You use vararg when you don't know how many of a particular type of argument will be passed to the method. It's a shortcut to creating an array manually.
Consider this function which has a list of arguments, including variadic and non-variadic arguments.
<?php
/**
* To use vararg, you follow the type of the last parameter by an ellipsis (three dots, ...),
* then a space, and the parameter name.
*
* For example:
*
* public Address (String... addr)
*
* Notice the token ... before the variable argument!
*
* It signifies that the argument length is unknown at design time!
* The actual argument list will be known at run-time when caller of
* this function passes in the exact number of arguments!
*
* Also, noted that you can mix both variadic and non-variadic arguments in any function,
* seperating them with commas!
*
* The method can then be called with any number of that parameter, including none.
* For example:
*
* public static void main(String[] arg)
* {
* new Address(); // none!
* }
*/
package mailinglist;
/**
* A contact is a name and address.
*
* For the purpose of this example, I have simplified matters
* a bit by making both of these components simple strings.
* In practice, we would expect Address, at least, to be a
* more structured type.
*/
class Address implements Cloneable
{
private String name;
private String streetAddress;
private String city;
private String state;
private String zipCode;
/**
* Constructor
*
* Create an address.
*
* Notice that addr is an array of unknown (argument) length
* The argument length will be passed in by the calling code
*
* For example:
*
* public static void main(String[] arg)
* {
* new Address("John Doe", "1234 Main St", "Minneapolis", "Minnesota", "55401");
* }
*/
public Address(String... addr)
{
/**
* Because addr is an array of unknown (argument) length we have to test
* the argument length that was passed in by the calling code
*
* Note that this testing of argument length is not the most elegant way to do it.
* But it illustrates the point!
*/
if addr[0] != -1)
{
this.name = addr[0].name;
}
if addr[1] != -1)
{
this.streetAddress = addr[1].streetAddress;
}
if addr[2] != -1)
{
this.city = addr[2].state;
}
if addr[3] != -1)
{
this.state = addr[3].state;
}
if addr[4] != -1)
{
this.zipCode = addr[4].zipCode;
}
}
?>
Here is another example to show how to use vararg.
First of all, let's illustrate the Point coordinate class to be used in the vararg:
<?php
public final class Point
{
// Point coordinates
final double x; // x-coordinate
final double y; // y-coordinate
// A Point constructor to initialized the point coordinates
public Point(double x, double y)
{
this.x = x;
this.y = y;
}
}
?>
Here is the illustration of the vararg using class Point (above) as the object type. Notice that variable corner is an argument of unknown length of coordinates.
In other words, you can pass in lots of coordinates at run-time but during design-time, it is unknown. All we know is that we can reference the x- and y-coordinates at design-time:
<?php
class Geometry
{
// code logic
public Polygon Area(Point... corner)
{
int numberOfSide = corner.length;
double squareOfSide, lengthOfSide;
squareOfSide = (corner[1].x - corner[0].x) * (corner[1].x - corner[0].x) +
(corner[1].y - corner[0].y) * (corner[1].y - corner[0].y);
lengthOfSide = Math.sqrt(squareOfSide);
// more method body code follows that creates and returns a
// polygon connecting the Point(s)
}
}
?>
You can see from the above illustration, inside the method Area, corner is treated like an array. The method (Area) can be called either with an array or with a sequence of arguments. The code in the method body will treat the parameter as an array in either case.
You will most commonly see vararg with the printing methods; for example, this Java built-in library printf() method:
public PrintStream printf(String format, Object... vararg)
{
// Java internal code implementation for printf()
}
// Now the function above allows you to print an arbitrary number of objects.
// It can be called like this:
System.out.printf("%s: %d, %s%n", name, idnum, address);
// Or it can be called like this as well:
System.out.printf("%s: %d, %s, %s, %s%n", name, idnum, address, phone, email);
// Or with yet a different number of arguments.
// The possibility is vast when you use vararg
?>
There you have it!!!
For a related topic on auto load and on how to use SPL auto load, please check out the 'how to build your own framework':
Advanced Pattern in MVC: Code Your Own PHP MVC FrameworkAutoloading of classes is a daily chore if you're a programmer. Every time you build an application (big or small) requires you to load your classes from the directories where classes are located. Most inexperienced programmers (or maybe all inexperienced programmers) typically load their classes at the class level rather than at the application level. Here is an example of loading of classes at a class level:
<?php
include '/home/package/someclass.php';
include_once '/home/package/someotherclass.php';
require '/home/package/somemoreclass.php';
require_once '/home/package/someothermoreclass.php';
/**
* An example of loading classes at a class level
*/
class MyClass extends OtherClass
{
// more code here
// .....
}
As you can see, this class loads four classes (someclass.php, someotherclass.php, somemoreclass.php, someothermoreclass.php) files at the top of the class file. This is called class level loading. This is the most popular way of doing for most of us programmers, including experienced and inexperienced programmers.
There is absolutely nothing wrong with class level loading and it can accomplish tasks (large or small) very well. However, pattern programming methodologies are becoming more and more popular and thus making use of application level loading even more mainstream.
Pattern programming methodologies such as the MVC pattern, loading of classes are taking place at the application level -- and that is, we don't put the include, include_once, require, or require_once at the top of every class or at anywhere in the class. Rather, it is autoloaded directly into the base class.
FYI: PHP's __autoload() is deprecated as of PHP 7.2.0 and its usage is discouraged.
So use SPL auto load instead.
The following description shows how SPL auto loads of classes.
SPL is short for Standard PHP Library, a collection of interfaces and classes that are meant to solve common problems. No external libraries are needed to build this extension and it is available and compiled by default in PHP 5.
SPL provides a set of standard datastructure, a set of iterators to traverse over objects, a set of interfaces, a set of standard Exceptions, a number of classes to work with files and it provides a set of functions like spl_autoload_register().
To auto load classes, there are two ways of doing it:
First, here is a simple version that uses an anonymous function to attempt to load the classes ExampleClass1 and ExampleClass2 from the files exampleclass1.php and exampleclass2.php, respectively. This is the simplest version you can use:
<?php
spl_autoload_register(function ($class_name)
{
// Of course, you need to specify a complete path to the
// class file
include $class_name . '.php';
}
);
?>
The code above registers anonymous function (along with its argument variable $class_name) with PHP (or SPL, to be more specific).
Now any time you create an instance of a class, like the following.
Also, don't forget to include the use clause at the top of your class file that refers/instantiates the classes. For example:
use app\controller\ExampleClass1;
use app\model\ExampleClass2;
$obj1 = new ExampleClass1();
Or
$obj2 = new ExampleClass2();
Or if classes are namespaced like these:
$obj1 = new app\controller\ExampleClass1();
Or
$obj2 = new app\model\ExampleClass2();
PHP (or SPL) will attemp to create an instance of the class, but if PHP doesn't recorgnize that class it will tries to load and include that class name specified in variable $class_name -- or classes ExampleClass1 and ExampleClass2 in this case.
Or if classes are namespaced, it's app\controller\ExampleClass1 and app\model\ExampleClass2.
Note: You should always use namespace on all of your classes when required as it is more robust and efficient. Also notice that,
'app' and 'controller' are actually folder names containing the models or classes (ExampleClass1, in this case). Likewise, 'app' and 'model' are the folder names containing the model 'ExampleClass2'
In other words, if PHP (or SPL) doesn't recorgnize that class it will call the anonymous function() above passing a string -- ExampleClass1 or ExampleClass2 -- to the anonymous function. Or if classes are namespaced, it will pass a string -- app\controller\ExampleClass1 or app\model\ExampleClass2 -- to the anonymous function.
Suppose you want to incorporate an spl_autoload functionality in your base class called Example. Here is how you would do it:
<?php
'path' and 'to' are actually folder names containing the models or classes
namespace path\to;
/**
* As you can see, in the above namespace statement, it points to a folder 'path/to'
*
* You'll see later, that the namespace like 'path\to' will be converted to a directory
* structure of the form: path/to/my/className. For example: path/to/my/ParentClass.
*
* Pay special attention to the 'use' clause as it allows class 'Example' to extend
* from class 'ParentClass'
*
* Now in class ParentClass, you need to namespace it so that class 'Example' can
* extend it by using the 'use' clause. For example, at the top of class ParentClass:
*
* namespace path\to;
*
* with 'path' being a folder named 'path' and 'to' also being
* a sub-folder named 'to'. Of course, you can name any name you wish!
*
* Now when PHP sees class 'Example', if it doesn't recorgnize it, it will call the
* anonymous function and passing the string 'Example' to it!
*
* Also, since class Example extends ParentClass, it will use that parent class by
* referring to the 'use' clause, and in effect, SPL calls the anonymous
* function as well and passing the string 'ParentClass' to it as well!
*
* So the key to a good programming practice is to use namespace on your classes!
*/
use path\to\ParentClass;
/**
* Example is the base class serving common functionalities.
*/
class Example extends ParentClass
{
// Using anonymous function, you can put spl_autoload_register() statement
// anywhere in your main base class including inside the constructor
// In an MVC pattern, you can put spl_autoload_register() statements inside
// the starting script file as well
spl_autoload_register(function ($class_name)
{
// Of course, you need to specify a complete
// path to the class file
// also, name all class files the same as
// their class names
// If you happen to read my other tutorial
// on 'coding standard', I lay out a reason
// by stating that it is very important
// that a file name MUST be the same as the
// class name!
// This is the reason why it has to be!
// In my coding standard I also suggest that
// all file names are in lowercase letters!
// However, it is NOT manditory! It's not "A MUST"!
// This is because I found that for some shared
// hostings, they think a lowercase file name is
// different than its camelcase class name and they
// give error: Class NOT Found!
// For example declaring classes like these:
// class MyApplication is different than class myapplication
// this difference is pertaining to shared hostings only
// and not pertaining to PHP language itself!
// so make note of that!
// In other words, it can't find a class with the same name
// as the lowercase file name.
// yes, it is weird! but be aware of it!
// it caused me a major headache until I realized the problems!
// This scenario is very rare, but it is out there
// and just be aware of it!
// If you see this error, try to rename your class
// file name in the same letter case as the
// class name.
// But in general, use lowercase letter for all
// file names
include $class_name . '.php';
}
);
}
?>
Here again, if PHP (or SPL) doesn't recorgnize the class that is being instantiated, it will call the anonymous function() inside class Example passing a string contains in the variable $class_name to the anonymous function. Remember that autoloading of classes is often being done in the base class or sometimes called base controller class.
Secondly, here is a more sophisticated version that uses a function name to autoload the classes. This is the preferred version if you're developing large-scale applications.
spl_autoload_register() allows you to register multiple functions (or static methods ['myAutoloader' in this case] from your own autoload class) that PHP will put into a stack/queue and call sequentially when PHP sees an unknown class being referenced or instantiated.
In other words, PHP (or SPL) will call a function name that has been registered in the spl_autoload_register() and tries to load and include that class name inside that function. For example:
<?php
spl_autoload_register('myAutoloader');
?>
That code above will register a function named 'myAutoloader' which is illustrated below:
So if you defined an autoload function named 'myAutoloader' [as shown below] and registered it in spl_autoload_register() [as shown above], PHP will call that function name whenever it sees an unknown class being referenced or instantiated. The two keywords that we're interested in are: referenced and instantiated. For example, when you reference or create an instance of a class, like so:
<?php
// here, we referenced MyClass and if PHP doesn't recorgnize this class it will
// call 'myAutoloader'
MyClass::$some_static_property_variable = $this;
// here, we create an instance of MyClass and if PHP doesn't recorgnize this class
// it will call 'myAutoloader'
$myClass = new MyClass();
Or if classes are namespaced like these:
// here, we referenced the namespaced MyClass and if PHP doesn't recorgnize this class
// it will call 'myAutoloader'
app\base\MyClass::$some_static_property_variable = $this;
// here, we created an instance of the namespaced MyClass and if PHP doesn't recorgnize
// this class it will call 'myAutoloader'
$myClass = new app\core\model\MyClass();
// likewise, we can reference the namespaced app\core\OtherClass via the 'extends' clause
// and if PHP doesn't recorgnize 'app\core\OtherClass' class it will call 'myAutoloader'
// using the 'use' clause that you include it at the top of your class!
// make sure to namespace your classes and use the 'use' clause to include it!
use app\core\OtherClass;
class MyClass extends app\core\OtherClass
?>
As you can see, whenever you instantiate a class or reference a class -- including via an extends clause, if PHP does not recorgnize the class (i.e., "MyClass" or app\core\OtherClass hasn't been instantiated and/or included) -- PHP will call a function named myAutoloader() and tries to include that class file inside that function named myAutoloader():
<?php
// PHP calls this function passing a class name as a string like so:
// myAutoloader("MyClass")
// or if a class contains a namespace it also does it accordingly:
// myAutoloader("app\core\MyClass")
function myAutoloader($className)
{
// you might want to create a folder named class and put all of your
// classes in it:
// $path = '/class/'
// this folder named class should be in the same directory as the
// entry point of your application.
// here, all classes should be inside directory /class/
$path = '/path/to/class/';
// if a class ($className) uses a namespace, the namespace will be
// converted into the directory structure, for example:
// namespace app\core\model\MyClass becomes app/core/model/MyClass
// the following statement replaces the characters "\" in the string
// $className with "/" to convert a namespace into a directory structure
// also, all class name/file (pair) need to be named the same
$filename = $path . str_replace("\\", '/', $className) . ".php";
if (file_exists($filename))
{
include($filename);
if (class_exists($className))
{
// we could do like this as well: return; // exit the function!
return TRUE; // exit the function!
}
}
return FALSE; // exit the function!
}
?>
In the example above, "MyClass" is the name of the class that you are trying to reference or instantiate, PHP passes this class name as a string to spl_autoload_register(), which allows you to pick up the variable ($className) and use it to "include" the appropriate class/file [as shown above].
As a result, you don't specifically need to include that class via an include/require statement. Just simply reference or instantiate the class you want to reference/instantiate like in the examples above, and since you registered a function (via spl_autoload_register()) of your own, PHP will call that function and it will figure out where all your classes are located.
Notice that this custom function is a function that you have to create and then register it in the SPL and if PHP doesn't recorgnize 'app\core\OtherClass' class it will call 'myAutoloader' autoloader.
Remember that autoloading of classes is often being done in the application's base class, sometimes called controller base class in an MVC pattern talk.
To register your custom auto load function, you typically put spl_autoload_register() statements in your main base helper class and call that class from inside the starting script file. For example:
File: '/myfirstproject/package/application.php'.
<?php
/**
* Application is the base helper class serving base class common functionalities.
*
* Notice that there is no namespace for this class Application because it doesn't
* need one!
*
* Remember that not all classes require a namespace and this one is an example
* of that!
*
* However, pay special attention to the 'use' clause as it allows class 'Application'
* to extend from parent class 'Example'
*
* Now in class Example, you need to namespace it so that class 'Application' can
* extend it by using the 'use' clause. For example, at the top of class Example:
*
* namespace path\to;
*
* with 'path' being a folder named 'path' and 'to' also being
* a sub-folder named 'to'. Of course, you can name any name you wish!
*
* Now when PHP sees class 'Application', it should recorgnize it because
* the starting script that uses this class will include it!
*
* Now, since class Application extends Example, it will use that parent class by
* referring to the 'use' clause, and in effect, SPL calls the function
* myAutoloader() as well and passing the string 'Example' to it as well!
*
* So the key to a good programming practice is to use namespace on your classes!
*
* Pay special attention also that, as stated earlier, you can register your autoloader
* anywhere (as the below shows)
*/
use path\to\Example;
class Application extends Example
{
/**
* As you can see, the class Application is empty! No content, whatsoever!
*
* This is because class Application extends from class Example and therefore
* it gets all of its functionalities from parent base class Example.
*
* Of course, if you need more functionalities that parent base class Example
* didn't provide, you can add them here as well! Nothing stops you from doing so!
*
* However, keep this class to an absolute minimum and clean and empty if possible!
*/
}
// PHP automatically registers the custom 'myAutoloader' function of
// the class 'Application'
// remember that class 'Application' extends from parent base class Example,
// and therefore, function myAutoloader is in parent class Example
spl_autoload_register('Application', 'myAutoloader');
/**
* As stated earlier, you can register your autoloader anywhere including in the same
* file.
*
* Notice that the autoloader is registered in the same class file as class Application,
* but outside of the class definition because we want to register the same class
* Application, so therefore, it has to be outside of the class Application definition.
*
* So from here, your starting script file index.php has to call/include this
* class Application, for example:
*
* require __DIR__ . '/path/to/application.php';
*/
?>
In the starting script file, typically in the index.php, you do it like the following.
Also, you might want to create a folder named class and put all of your classes in it. This folder named class should be in the same directory as the entry point of your application. In this case, inside the main project folder called /myfirstproject/. For example: /myfirstproject/class/:
File: '/myfirstproject/index.php'.
<?php
/**
* The main index.php starting script file
*
* Notice that there is no need to use the 'use' clause in the starting
* script file: index.php
*
* You do it the old fashion way using:
*
* require(), require_one(), include(), include_one()
*/
// loads the helper class: '/myfirstproject/package/application.php'
// __DIR__ points to the root directory: /myfirstproject/ or whatever you name it!
require __DIR__ . '/package/application.php';
// of course, there should be other classes/code to load as well!
$app = new Application();
// notice that the call to init() is actually calling Example's
// init() because class Application extends from class Example
$app->init();
?>
Assuming Example is an application's base class, here is how you would implement your own custom auto load function:
<?php
/**
* Example is the base class serving common functionalities.
*
* In my other tutorial called "advanced pattern programming: MVC,
* this class 'Example' is equivalent to base class Base()
*
* the "extends ParentClass" is a fake class! So either you omit it or
* implement it accordingly according to your parent class logic!
* for beginners, I recommend you to just remove it entirely!
*
* Notice the namespace of the class Example.
* Notice the use of the 'use' clause as well!
*/
namespace path\to;
use path\to\ParentClass;
// notice that you could namespace the class Route as well and
// use that namespace here!
// use path\to\route;
class Example extends ParentClass
{
// this init() is to call class route's init()
public function init()
{
// notice that you could namespace the class Route as well!
// I'm being very lazy here and forget to namespace it!
// __DIR__ points to the root directory:
// /myfirstproject/ or whatever you name it!
require __DIR__ . '/route/route.php';
$route = new route();
// the following code executes method init() of class route
// see my other tutorial called "advanced pattern programming: MVC
$route->init();
}
// PHP automatically calls this function along with passing in
// a class name as a string
public function myAutoloader($className)
{
// you could put classes in different folders for modularity purpose, for example,
// the following $root code is for non-namespaced classes only, i.e., MyClass, Person, etc.
// actually, you can even put both namespaced and non-namespaced classes in these
// folders mixing them together and it will load them accordingly
// for namespaced classes it is automatically converted into its
// own directory stucture without you having to specify it explicitly
// for non-namespaced classes it will also load them "AS IS" as specified in
// the following in the $root code below!
// for example, the following code is mainly for non-namespace classes,
// however, you can put namespaced classes in the following folders as well:
$root = [
$_SERVER['DOCUMENT_ROOT'] . DIRECTORY_SEPARATOR . 'resource/',
$_SERVER['DOCUMENT_ROOT'] . DIRECTORY_SEPARATOR . 'component/',
$_SERVER['DOCUMENT_ROOT'] . DIRECTORY_SEPARATOR . 'module/',
$_SERVER['DOCUMENT_ROOT'] . DIRECTORY_SEPARATOR . 'model/',
$_SERVER['DOCUMENT_ROOT'] . DIRECTORY_SEPARATOR . 'view/',
$_SERVER['DOCUMENT_ROOT'] . DIRECTORY_SEPARATOR . 'controller/',
$_SERVER['DOCUMENT_ROOT'] . DIRECTORY_SEPARATOR . 'helper/',
$_SERVER['DOCUMENT_ROOT'] . DIRECTORY_SEPARATOR . 'cart/',
$_SERVER['DOCUMENT_ROOT'] . DIRECTORY_SEPARATOR . 'mailer/',
$_SERVER['DOCUMENT_ROOT'] . DIRECTORY_SEPARATOR . 'vendor/',
$_SERVER['DOCUMENT_ROOT'] . DIRECTORY_SEPARATOR . 'miscellaneous/'
];
// as stated above, you can put both namespaced and non-namespaced classes
// in the above folders, mixing them together and it will load them accordingly
// however, for namespaced classes, you have to namespace them accordingly according
// to the folder levels. for example, for $_SERVER['DOCUMENT_ROOT'] . DIRECTORY_SEPARATOR . 'resource/',
// it is: namespace path\to\resource;
// with path\to\ being the $_SERVER['DOCUMENT_ROOT'] . DIRECTORY_SEPARATOR
// the trick is to specify the exact path to resource directory structure without using
// the global variable $_SERVER['DOCUMENT_ROOT'] . DIRECTORY_SEPARATOR
// now preserve the original class name before turning it into
// a directory structure
$class = $className;
/**
* first, we need to test to see if there is a namespace in variable
* $className, i.e., \core\model\MyClass
*
* if there is a namespace in variable $className, then we can go ahead
* and do the conversion and trimming
*
* if not, in the "else" clause, we use the class name contains in
* variable $className "AS IS" for example: MyClass
*
* second, the statement below converts a namespace into a directory structure.
* remember that SPL passes a raw namespace in its entire format and so we
* need to convert that raw namespace into a proper directory structure so
* that it can find where the files are located.
*
* $className with "\" to convert a namespace into a directory structure.
*
* for example, a namespace like this: 'path\to' will be converted to 'path/to'
*
* third, trim the left "/" resulted from converting
* namespace to a directory structure, for example:
* /core/model/MyClass becomes core/model/MyClass.
*/
// if there is a namespace in variable $className, i.e., \core\model\MyClass
if (strpos($className, "\\") !== false)
{
// we have a namespace class
$str = ltrim(str_replace("\\", DIRECTORY_SEPARATOR, $className), '/');
// namespaced classes are automatically converted into
// their own directory stucture without you having to specify them explicitly
// use the newly created directory structure to form a file path
$file = $str . '.php';
if (file_exists($file))
{
include($file);
// after the include statement, we can just exit the loop and the function,
// we don't want the loop to go on!
// we could do like this right here:
// return;
// we don't even need the following 'if' condition!
// well, maybe we do!
// it's up to your preference!
// either way it will work!
if (class_exists($file)) // core/model/MyClass
{
// we could do like this as well:
// return; // exit the loop and the function, we don't want the loop to go on!
return TRUE; // exit the loop and the function, we don't want the loop to go on!
} // end class_exists
} // end file_exists
} // end if namespace
else
{
// no namespace class
foreach ($root as $path)
{
// you could put classes in different folders for modularity purpose
// like the illustration in $root above!
// this is for non-namespaced classes only, i.e., MyClass, Person, etc.
$file = $path . $className . '.php';
// for namespaced classes only, i.e., core/model/MyClass, etc., the "if" statement is false
// actually, for all namespaced classes, they won't even come here at all
if (file_exists($file))
{
include($file);
// after the include statement, we can just exit the loop and the function,
// we don't want the loop to go on!
// we could do like this right here:
// return;
// we don't even need the following 'if' condition!
// well, maybe we do!
// it's up to your preference!
// either way it will work!
if (class_exists($file)) // MyClass
{
// we could do like this as well:
// return; // exit the loop and the function, we don't want the loop to go on!
return TRUE; // exit the loop and the function, we don't want the loop to go on!
} // end class_exists
} // end file_exists
} // end foreach()
return FALSE; // exit the function after exhausting the loop without any luck!
} // end "else" if (strpos($className, '\\') !== false)
} // end myAutoloader()
} // end class Example
?>
In the above base class Example, if somewhere in your application [most likely in the controller], you reference or create an instance of any class, like so:
<?php
// here, we referenced MyClass and if PHP doesn't recorgnize this class it will
// call 'myAutoloader'
MyClass::$some_static_property_variable = $this;
// here, we create an instance of MyClass() and if PHP doesn't recorgnize this class
// it will call 'myAutoloader'
$myClass = new MyClass();
?>
PHP will trigger a call to the function myAutoloader($className) above passing along the class name MyClass as a string to the function. As a result, that class gets included and instantiated.
The benefit of using spl_autoload_register() is that -- unlike PHP's __autoload() (which is deprecated as of PHP 7.2.0) -- you don't need to implement an autoload function in every file that you create or use the include, include_once, require, or require_once at the top of every class or at anywhere in the class.
<?php
/**
* 'Autoloader', 'Helper', 'Database' are class names.
* Notice that you can place autoloaders in the same class as well:
* 'ClassLoader', 'LibraryLoader'
*
* In my other tutorial called "advanced pattern programming: MVC,
* this class 'Example' is equivalent to base class Base()
*
* the "extends fromParentClass" is a fake class! So either you omit it
* or implement it accordingly according to your parent class logic!
* for beginners, I recommend you to just remove it entirely!
*/
namespace path\to;
use path\to\fromParentClass;
class Example extends fromParentClass
{
// register classes and their functions
public function __construct()
{
// Load a class: 'Autoloader' is the class name,
// 'ClassLoader' is the name of a function
spl_autoload_register('Autoloader::ClassLoader');
// Load a library: 'LibraryLoader' is the name of a function
spl_autoload_register('Autoloader::LibraryLoader');
// Load a helper class: 'Helper' is the name of the class
spl_autoload_register('Helper::HelperLoader');
// Load a database: 'DatabaseLoader' <== name of a function
spl_autoload_register('Database::DatabaseLoader');
}
}
?>
Here is the implementation of the class Autoloader:
<?php
/**
* Autoloader is the class libraries.
*
* the "extends fromOtherParentClass" is a fake class! So either you omit
* it or implement it accordingly according to your parent class logic!
* for beginners, I recommend you to just remove it entirely!
*/
namespace path\to;
use path\to\fromOtherParentClass;
class Autoloader extends fromOtherParentClass
{
// PHP automatically calls this function along with passing in
// a class name as a string
public function ClassLoader($className)
{
// so here, all classes should be in directory /class/
// make sure to namespace them accordingly and "use" them accordingly
// see the earlier illustration in $root above for more guiden!
$path = '/path/to/class/';
/**
* first, we need to test to see if there is a namespace in variable
* $className, i.e., \core\model\MyClass
*
* if there is a namespace in variable $className, then we can go ahead
* and do the conversion and trimming
*
* if not, in the "else" clause we use the class name contains in
* variable $className "AS IS" for example: MyClass
*
* second, the statement below converts a namespace into a directory structure.
* remember that SPL passes a raw namespace in its entire format and so we
* need to convert that raw namespace into a proper directory structure so
* that it can find where the files are located.
*
* $className with "\" to convert a namespace into a directory structure.
*
* for example, a namespace like this: 'path\to' will be converted to 'path/to'
*
* third, trim the left "/" resulted from converting
* namespace to a directory structure, for example:
* /core/model/MyClass becomes core/model/MyClass.
*/
// if there is a namespace in variable $className, i.e., \core\model\MyClass
if (strpos($className, "\\") !== false)
{
// we have a namespace class
$str = ltrim(str_replace("\\", DIRECTORY_SEPARATOR, $className), '/');
// use the newly created directory structure to form a file path
$file = $str . '.php';
if (file_exists($file))
{
include($file);
// after the include statement, we can just exit the loop and the function,
// we don't want the loop to go on!
// we could do like this right here:
// return;
// we don't even need the following 'if' condition!
// well, maybe we do!
// it's up to your preference!
// either way it will work!
if (class_exists($file)) // core/model/MyClass
{
// we could do like this as well:
// return; // exit the loop and the function, we don't want the loop to go on!
return TRUE; // exit the loop and the function, we don't want the loop to go on!
} // end class_exists
} // end file_exists
} // end if namespace
else
{
// no namespace class
// you could put classes in different folders for modularity
// like the illustration in $root directory example earlier!
// this is for non-namespaced classes only, i.e., MyClass, Person, etc.
$file = $path . $className . '.php';
if (file_exists($file))
{
include($file);
// after the include statement, we can just exit the loop and the function,
// we don't want the loop to go on!
// we could do like this right here:
// return;
// we don't even need the following 'if' condition!
// well, maybe we do!
// it's up to your preference!
// either way it will work!
if (class_exists($file)) // MyClass
{
// we could do like this as well:
// return; // exit the loop and the function, we don't want the loop to go on!
return TRUE; // exit the loop and the function, we don't want the loop to go on!
} // end class_exists
} // end file_exists
} // end "else" if (strpos($className, '\\') !== false)
return FALSE; // exit the function!
} // end function ClassLoader()
}
?>
The other classes are implemented in the same fashion. Self-explanatory.
Let's see some more examples to help you get the right idea and heading in the right direction.
In the starting script file, typically in the index.php, is where you typically register your SPL autoload. For example:
File: '/mysecondproject/index.php'.
<?php
/**
* The main index.php starting script file
*/
// notice that __DIR__ points to the root directory or
// 'mysecondproject'
// loads the auto load class from directory /class/ or
// from wherever you put it!
require __DIR__ . '/class/autoloadclass.php';
// of course, there should be other classes/code to load as well!
// but for this example, loading Base() class is all we need!
// I could have namespace the class Base and use it here: use path\to\Base;
require __DIR__ . '/base/base.php';
// notice that we can register the SPL anywhere including
// in the index.php starting script file
// the first parameter is the class that contains the autoload()
// the second parameter is the actual autoload function
/**
* Note that spl_autoload_register() will look for class AutoloadClass in the same
* directory as it is being registered, which is in this starting script file: index.php.
*
* So make sure that you put class AutoloadClass at the same level in directory as
* this starting script file: index.php.
*/
spl_autoload_register('AutoloadClass', 'autoload');
// of course, there should be other code logic as well such as
// a call to [start()] to kickstart your application!
// but for this example, we'll call to init() of class Base()
// see my other tutorial called "advanced pattern programming: MVC"
$base = new Base();
// the call to init() will kickstart the whole application
$base->init();
// that is it! very simple!
?>
That is it for the starting script. Now we can just go ahead and write an autoload class containing its autoload function. For example:
File: '/class/autoloadclass.php'.
<?php
/**
* AutoloadClass definition.
*
* No need a namespace for class AutoloadClass!
*
* Make sure that you put this class AutoloadClass at the same level in directory as
* your starting script file: index.php.
*/
class AutoloadClass
{
// PHP automatically calls this function along with passing in a
// class name as a string
public function autoload($className)
{
// so here, all classes should be in directory /class/
$path = '/path/to/class/';
/**
* first, we need to test to see if there is a namespace in variable
* $className, i.e., \core\model\MyClass
*
* if there is a namespace in variable $className, then we can go ahead
* and do the conversion and trimming
*
* if not, in the "else" clause we use the class name contains in
* variable $className "AS IS" for example: MyClass
*
* second, the statement below converts a namespace into a directory structure.
* remember that SPL passes a raw namespace in its entire format and so we
* need to convert that raw namespace into a proper directory structure so
* that it can find where the files are located.
*
* $className with "\" to convert a namespace into a directory structure.
*
* for example, a namespace like this: 'path\to' will be converted to 'path/to'
*
* third, trim the left "/" resulted from converting
* namespace to a directory structure, for example:
* /core/model/MyClass becomes core/model/MyClass.
*/
// if there is a namespace in variable $className, i.e., \core\model\MyClass
if (strpos($className, "\\") !== false)
{
// we have a namespace class
$str = ltrim(str_replace("\\", DIRECTORY_SEPARATOR, $className), '/');
// use the newly created directory structure to form a file path
$file = $str . '.php';
if (file_exists($file))
{
include($file);
// after the include statement, we can just exit the loop and the function,
// we don't want the loop to go on!
// we could do like this right here:
// return;
// we don't even need the following 'if' condition!
// well, maybe we do!
// it's up to your preference!
// either way it will work!
if (class_exists($file)) // core/model/MyClass
{
// we could do like this as well:
// return; // exit the loop and the function, we don't want the loop to go on!
return TRUE; // exit the loop and the function, we don't want the loop to go on!
} // end class_exists
} // end file_exists
} // end if namespace
else
{
// no namespace class
// you could put classes in different folders for modularity
// like the illustration in $root directory example earlier!
// this is for non-namespaced classes only, i.e., MyClass, Person, etc.
$file = $path . $className . '.php';
if (file_exists($file))
{
include($file);
// after the include statement, we can just exit the loop and the function,
// we don't want the loop to go on!
// we could do like this right here:
// return;
// we don't even need the following 'if' condition!
// well, maybe we do!
// it's up to your preference!
// either way it will work!
if (class_exists($file)) // MyClass
{
// we could do like this as well:
// return; // exit the loop and the function, we don't want the loop to go on!
return TRUE; // exit the loop and the function, we don't want the loop to go on!
} // end class_exists
} // end file_exists
} // end "else" if (strpos($className, '\\') !== false)
return FALSE; // exit the function!
} // end function autoload()
}
?>
Let's see some more examples to help you get the right idea and heading in the right direction.
In the starting script file, typically in the index.php, is where you typically register your SPL autoload. For example:
File: '/mythirdproject/index.php'.
<?php
/**
* The main index.php starting script file
*/
// notice that __DIR__ points to the root directory or
// 'mythirdproject'
// load the helper class from the root directory /mythirdproject/
require __DIR__ . '/application.php';
// of course, there should be other classes/code to load as well!
// but for this example, loading Application() class is all we need!
// include our helper class: Application() from the 'mythirdproject' folder
// notice that we can register the SPL anywhere including
// in this index.php starting script file as well as in a
// helper class Application as you'll see later in another example.
// sort of an extension to the main base class similar to class Base()
/**
* Note that spl_autoload_register() will look for class AutoloadClass in the same
* directory as it is being registered, which is in this starting script file: index.php.
*
* So make sure that you put class AutoloadClass at the same level in directory as
* this starting script file: index.php.
*/
// the first parameter is the class that contains the autoload()
// the second parameter is the actual autoload function
spl_autoload_register('AutoloadClass', 'autoload');
// of course, there should be other code logic as well such as
// a call to [start()] to kickstart your application!
// but for this example, we'll call to start() of class Main()
// notice that the call to start() will refer to class Main's start()
// you'll have to create a function called start() in your class Main
// this start() is similar to function init() in class Base() in my
// other tutorial called "Introduction to Advanced Pattern: MVC"
$app = new Application();
// the call to start() will kickstart the whole application
$app->start();
// that is it! very simple!
?>
That is it for the starting script. Now we can just go ahead and write a helper class that helps our main application class Main to extend its functionalities further. For example:
File: '/mythirdproject/application.php'.
<?php
/**
* Make note of the require statement below. It's at the top of the file,
* outside of the class and not inside of the class.
*
* Although you can put it inside the class, but outside the class is the
* more preferrable place because it is available/visible in the entire file,
* not just inside the class.
*
* If you put it inside the class you would have to create an instance
* of the class in order for the require statement to take effect.
*
* So putting it at the top of the class and outside of the class is
* the most preferrable spot because it is available/visible in the entire
* file, not just inside the class.
*/
// include our base class: Main() from the 'mythirdproject' folder
// we could use the namespace instead of this: require __DIR__ . '/main.php';
/**
* Class Aplication definition.
* Aplication is a helper class serving common application functionalities
*/
use path\to\Main;
class Aplication extends Main
{
// As you can see for this example, this helper class is empty!
// It gets all of its functionalities from parent class 'Main'
// If you need more functionalities that parent class Main didn't provide,
// you can add them here in this helper class!
// But for this example, it is left empty and it is just fine because
// we don't need any more functionalities!
// That is it for the helper class!
// It is blank!
}
// notice that we can register the SPL anywhere including
// in the index.php starting script file as well as in here outside
// of a helper class Application base class.
// preferrably putting the SPL right here outside the class [as appose to
// inside this class definition or inside index.php starting file.]
// notice that it is "outside" of this helper class definition but in the same file!
// the first argument is the class name and the second is the function name!
// note also that function 'autoload' is in parent class Main
// right here "outside" of the helper class definition is the most preferrable spot
// and in the same file: '/mythirdproject/application.php'
// it is perfectly legal!
spl_autoload_register('Main', 'autoload');
?>
Now all you have to do is instantiating this helper class and you get all of the functionalities from the parent class without having to refer or instantiating the parent class Main. You should never have to do anything with the base parent class Main - you do all of your programming work in the child classes of Main, like this child class Application.
Also, you shouldn't have to have more than one child class of Main. Just create one child class of Main like child/helper class Application and you're good to go.
So in a sense, child class like Application acts like a main application class that handle all of your functionalities even though it is practically empty.
Keep this child class to a very minimum and clean (as you can see: it's empty) and provide all of the functionalities in the parent class.
As stated above, all you have to do is instantiating this helper/child class Application and you're good to go. You should never have to instantiating the base parent class Main at all - you do it in this child class Application.
Now here is our main application base class Main similar to Base class in my other tutorial called "Introduction to Advanced Pattern: MVC". For example:
File: '/mythirdproject/main.php'.
<?php
/**
* Class Main definition.
* Main is the base main class serving common application functionalities
*
* This class is similar to Base class in my other tutorial called
* "Introduction to Advanced Pattern: MVC"
*/
namespace path\to;
class Main
{
// As you can see, this is the base class for the whole application!
// It has all the functionalities required to build an application!
// If you need more functionalities than this base parent class provides,
// you can add them in the child helper class that extends from this class!
// See helper class Application earlier!
// For this example I won't provide all the functionalities required by a
// normal base class would! Only a few key points about kickstarting capabilities!
// A typical base class, sometimes called main base controller class in an MVC
// scheme of thing, it should contains the setter, getter, and autoload
// functions, at the very least!
// How you implement your main base controller class is up to you!
// But just remember that your main base controller class is suppose to
// contain and handle all of the application's functionalities!
// But here are some of the key ingridients that should be in the base class:
// the constructor
public function __construct();
{
// constructor code logic
}
// kickstart the ball rolling by grabbing the http request!
public start();
{
// start() code logic
// you should grab the HTTP REQUEST from getRequest() below and
// process its route/controller/action accordingly as well as
// dispatching those route/controller/action to their proper destination!
}
// the parameter is the class name passed in by PHP's SPL
public autoload($className);
{
// auto loading code logic
}
public set($param, $value);
{
// set() code logic
}
public get($param);
{
// get() code logic
}
public createController();
{
// createController() code logic
}
public getModel($param);
{
// getModel() code logic
}
public getAction($param);
{
// getAction() code logic
}
// process HTTP REQUEST
public getRequest($param);
{
// getRequest() code logic
// process the HTTP REQUEST code logic, such as parsing the url and
// return the values as an array to the caller!
}
}
?>
Here is another example to help you get the right idea and heading in the right direction.
This is another autoload function that you can use SPL auto load functionality to call this function (autoloader()) using values of a configuration file path. For example:
File: '/myfourthproject/autoloader.php'.
<?php
/**
* An autoloader function
*
* This function is a little bit complex than the prior ones shown earlier!
*/
// $name is the class name passed in by SPL everytime SPL calls this function
public function autoloader($name)
{
// get all the possible paths to the file
// (that is preloaded with the file structure of the project)
// for init_get(), please see:
// https://www.php.net/manual/en/function.ini-get.php
$path = explode(":", ini_get('include_path'));
// for 'include_path', see your php.init file
// it goes something like this: include_path = ".;c:\php\includes"
// please see PHP's: set_include_path() as well!
// see ini_set('include_path', ini_get('include_path')
// loop through for each possible path to the file
foreach ($path as $tryThis)
{
// try each possible iteration of the file name and
// use the first one that comes up, for example:
// name.class.php
$exist = file_exists($tryThis . '/' . $name . '.class.php');
if ($exist)
{
include_once($name . '.class.php');
return; // exit the function
}
// if the above condition is false, it should come here!
// ok that didn't work, try the other way around
$exist = file_exists($tryThis . '/' . 'class.' . $name . '.php');
if ($exist)
{
include_once('class.' . $name . '.php');
return; // exit the function
}
// if the above condition is false also, it should come here!
//neither did that...let's try as an inc.php
$exist = file_exists($tryThis . '/' . $name . '.inc.php');
if ($exist)
{
include_once($name . '.inc.php');
return; // exit the function
}
}
// if all three of the above conditions are false, it should come here!
// can't find the class passed in by SPL ...
die("Class $name could not be found!");
}
?>
That is it!
Very simple to implement your own SPL auto load application.
For more see spl autoload. FYI: PHP's __autoload() is deprecated as of PHP 7.2.0 and its usage is discouraged.
First of all, a namespace is a file directory conflict resolution methodology, resolving file directories to avoid naming conflicts. For example, there are lots of situations where you use libraries from third parties that have the same class names, the same file names, the same directory names, etc., as your class names, your file names, your directory names, respectively, and this will cause conflicts among the third party librabries and your own libraries.
For example, if I write an application library, say, a very huge and sophisticated MVC library and allow you to download and use my MVC library, there are bound to be some class names in my library that might have the same name as your own application and this will cause either my library to not working properly or it will cause your own application not to work properly because of the conflict between the two libraries.
To solve this problem, a namespace was invented.
Secondly, the difference between namespace and __NAMESPACE__ is that namespace is just a keyword used to declare the namespace while __NAMESPACE__ is just a constant of the namespace used to refer to the declared namespace.
I'm a little lazy; and therefore, I will refer you to these excellent tutorials on the Web:
namespace keyword and __NAMESPACE__ constant
Namespacing, use and group use declarations in PHP
There you have it! Go at it full bore!!
First of all, we'll leave realpath() to be discussed last.
Usage: include (dirname(__FILE__) . '/file.php');
Usage: include (__DIR__ . '/file.php');
Both cases achieve the same thing and their usages are identical! So there is no different between the two. You can use either of the two and you're good to go.
However, __DIR__ is faster and more efficient than dirname(__FILE__). So using __DIR__ rather than dirname(__FILE__) is strongly recommended.
Both __DIR__ and dirname(__FILE__) load the parent current (absolute) path.
So what exactly does it mean to load the parent current path? Answer: It just means the current directory!
Using the following as an illustration, suppose we have a root folder named 'project' that contains a main file named index.php. Inside the project folder we also have two direct children folders, one named inc and the other named web.
Directory project also has grandchildren/great grandchildren folders/files, or more specifically, directory project has three grandchildren folders named: model, view, and controller along with their files.
Directory project also has one great grandchild folder named: helper along with its file7.php and file8.php.
Now let's focus our attention mainly in the two direct children of directory project: inc and web. Inside the child folder inc we have two files: file1.php and file2.php. And likewise, inside the child folder web we also have two files: file3.php and file4.php.
Disregard the model, view, and controller for now.
<?php
project
|-- index.php
|
|-- inc
| +-- file1.php
| +-- file2.php
|
|-- web
| +-- file3.php
| +-- file4.php
|
|
| +-- model
| +-- file5.php
|
| +-- helper
| +-- file7.php
| +-- file8.php
|
| +-- view
| +-- file9.php
|
| +-- controller
| +-- file10.php
|
?>
To start, you'll need to find out what directory the current file is in, because this is the file we're concerned about. In other words, under what directory is your file residing in? Knowing what directory your file is in, you can look up the path of that file.
Using the above illustration as an example, index.php is in the parent directory named 'project'; while file1.php and file2.php both are in a parent directory named 'inc'; and file3.php and file4.php both are in a parent directory named 'web'.
So the current file directory in respect to 'index.php' is 'project' and that is the parent current (absolute) path of the file 'index.php':
Likewise, the current file directory in respect to 'file1.php' and 'file2.php' is 'inc'; the current file directory in respect to 'file3.php' and 'file4.php' is 'web'.
So 'project', 'inc', and 'web' are parent directories for their relevant children folders/files. So to load a parent current directory path means to load 'project/' if we're working inside index.php file. Likewise:
<?php
load 'project/inc/' if we're inside file1.php trying to use /file2.php., e.g.:
include (__DIR__ . '/file2.php');
Basically, __DIR__ loads file1.php's parent current directory which is 'project/inc/'.
file2.php is in the same directory as file1.php and no further reference is necessary.
So it becomes: include ('project/inc/file2.php')
Likewise, the same thing can be said about the remaining three cases:
load 'project/inc/' if we're working inside file2.php, e.g., include(__DIR__ . '/file1.php');
load 'project/web/' if we're working inside file3.php, e.g., include(__DIR__ . '/file4.php');
load 'project/web/' if we're working inside /file4.php, e.g., include(__DIR__ . '/file3.php');
?>
The thing that confuses people the most is that they throw in the word 'parent' in addition to the word 'current' when they really just mean the 'current' directory. Period! So to load a 'parent current' directory path can be said to load a 'current' directory path.
Now knowing that we can use either __DIR__ or dirname(__FILE__) to find the 'current' directory path. For example:
<?php
assuming a script that is at the same level as 'index.php' and trying to use 'index.php':
include (__DIR__ . '/index.php');
as you can see __DIR__ loads 'project/'
now assuming a script 'index.php' trying to use 'file7.php' or 'file8.php':
include (__DIR__ . '/web/model/helper/file7.php');
include (dirname(__FILE__) . '/web/model/helper/file7.php');
include (__DIR__ . '/web/model/helper/file8.php');
include (dirname(__FILE__) . '/web/model/helper/file8.php');
notice that __DIR__ and dirname(__FILE__) both loads project/ directory.
now assuming a script that is at the same level as 'file1.php' and trying to use 'file1.php'.
let's put it this way: assuming 'file1.php' is trying to use 'file2.php':
include (__DIR__ . '/file2.php');
include (dirname(__FILE__) . '/file2.php');
now assuming 'file2.php' is trying to use 'file1.php':
include (__DIR__ . '/file1.php');
include (dirname(__FILE__) . '/file1.php');
now all four cases __DIR__ and dirname(__FILE__) load 'project/inc/'
now assuming a script that is at the same level as 'file3.php' and trying to use 'file3.php':
include (__DIR__ . '/file3.php');
include (dirname(__FILE__) . '/file3.php');
both cases __DIR__ and dirname(__FILE__) load 'project/web/'
now assuming a script that is at the same level as 'file5.php' and trying to use 'file5.php':
include (__DIR__ . '/file5.php');
include (dirname(__FILE__) . '/file5.php');
both cases __DIR__ and dirname(__FILE__) load 'project/web/model/'
now assuming a script that is at the same level as 'file7.php' and trying to use
'file7.php' or 'file8.php'.
let's put it this way: assuming 'file7.php' is trying to use
'file8.php':
include (__DIR__ . '/file8.php');
include (dirname(__FILE__) . '/file8.php');
now assuming 'file8.php' is trying to use
'file7.php':
include (__DIR__ . '/file7.php');
include (dirname(__FILE__) . '/file7.php');
both cases __DIR__ and dirname(__FILE__) load 'project/web/model/helper/' because both
file7.php and file8.php are at the same level of directory and only __DIR__ and
dirname(__FILE__ are needed.
now assuming a script that is at the same level as 'file9.php' and trying to use
'file9.php'.
again, this is the same as the above cases where both files are at the same level and no
further up in directories are needed to reference:
include (__DIR__ . '/file9.php');
include (dirname(__FILE__) . '/file9.php');
both cases __DIR__ and dirname(__FILE__) load 'project/web/view/'
now assuming a script that is at the same level as 'file10.php' and trying to use
'file10.php':
include (__DIR__ . '/file10.php');
include (dirname(__FILE__) . '/file10.php');
both cases __DIR__ and dirname(__FILE__) load 'project/web/controller/'
?>
Now to reach out to other directories outside of current parent directory, you will have to get out (/../) of your own parent directory:
<?php
load 'project/web/' if we're working inside file1.php and want to use file3.php,
e.g., include (__DIR__ . '/../web/file3.php');
Here, we're inside file1.php trying to use file3.php. But file1.php and file3.php are
in their own seperate parent directory.
So file1.php has to get out of its own parent directory traversing backward one step or
one directory level up to be at the same level as file3.php's parent directory.
In other words, file1.php has to traverse backward to be at the same level as index.php,
inc, and web. So traversing one step backward (/../) is good enough to be at the same
level as index, inc, and web.
Traversing backward is denoted as /../ which is counted as one step backward or
one directory level up.
/../, /../../, and /../../../ are called symbolic links.
/./ (or one-dot) is called no symbolic link.
If you ever come across someone's code that looks something like this:
<a href="./index.html">Home</a>
or
<link href="./css/style.css" rel="stylesheet">
or
<script src="./project/js/jquery.js">
It means no symbolic link. It means/works the same thing as these:
<a href="index.html">Home</a>
or
<link href="css/style.css" rel="stylesheet">
or
<script src="project/js/jquery.js">
Going up two directory levels up: /../../
Going up three directory levels up: /../../../
Now once you're at the same level as 'web' you can go down one step to find file3.php.
But you need to tell the script where to traverse to, hence, the /web/ reference:
include (__DIR__ . '/../web/file3.php');
So in effect __DIR__ equals to 'project/inc/' because we're inside file1.php.
So __DIR__ basically points to the directory leading up to file1.php.
Now at this time we're at 'project/inc/'
But we want to go one step backward.
So in effect /../ takes one step backward to be at 'project'.
So in effect __DIR__ . '/../' equals to 'project'.
So right now we're at 'project'.
But we still need to go forward to find file3.php, so a reference to /web/ is required.
Hence, the /web/file3.php was included in the statement above.
So include (__DIR__ . '/../web/file3.php') becomes: include ('project/web/file3.php')
Now our mission is accomplished!
The remaining three cases can be illustrated in the same fashion:
load 'project/web/' if we're working inside file2.php and
want to use file4.php, e.g., include (__DIR__ . '/../web/file4.php');
load 'project/inc/' if we're working inside file3.php and
want to use file1.php, e.g., include (__DIR__ . '/../inc/file1.php');
load 'project/inc/' if we're working inside file4.php and
want to use file2.php, e.g., include (__DIR__ . '/../inc/file2.php');
?>
If we do an include "inc/file1.php" from index.php it will work. However, if we do an include "inc/file2.php" from inside file1.php to include file2.php, it won't work, because "inc/file1.php" is at the same directory level as "inc/file2.php". The latter was a trick to throw people off guard using "inc/".
Likewise, from the index.php perspective, include "inc/file2.php", will work.
__DIR__ fixes this, so from file1.php we can do this:
<?php
include (__DIR__ . "/file2.php");
?>
Like dirname(__FILE__), __DIR__ also loads the parent current (absolute) path relative to the current file being worked on. For example, in the example above, we're working on index.php and inside this index.php perspective that we're currently referring to as the current working directory.
So up to the current directory or the current working directory is where both dirname(__FILE__) and __DIR__ are specifically designed to handle the leading parent directory.
For example, inside file1.php, you don't have to specify 'project/inc/file2.php' to use file2.php. You can specify __DIR__ . 'file2.php' and __DIR__ will take care of the proper hierarchical levels of directory.
Likewise, inside file3.php, you don't have to specify 'project/web/file4.php' to use file4.php. You can specify __DIR__ . '/file4.php' and __DIR__ will take care of the proper hierarchical levels of directory.
So from the perspective of file1.php or file3.php, it retreats back to the parent's current directory and move down to find file2.php or file4.php, respectively. __DIR__ takes care of the proper hierarchical levels of directory up to the current working directory:
<?php
include (__DIR__ . '/file2.php');
include (__DIR__ . '/file4.php');
?>
Now, how do we include files file3.php and file4.php from file1.php or file2.php or include file1.php and file2.php from file3.php or file4.php?
__DIR__ fixes this, so from file1.php and file2.php we can do this:
<?php
include (__DIR__ . "/../web/file3.php");
include (__DIR__ . "/../web/file4.php");
?>
From file3.php and file4.php we can do this:
<?php
include (__DIR__ . "/../inc/file1.php");
include (__DIR__ . "/../inc/file2.php");
?>
As for dirname(__FILE__), it returns the directory of current included file -- the file that is being worked on currently in the current directory.
To get the directory of current included files you can use dirname(__FILE__).
For example, if a script called 'file2.php', which is in the sub-directory 'inc', wants to include the script 'file1.php', you can use:
<?php
dirname(__FILE__) . 'file1.php');
?>
<?php
dirname(__FILE__) . 'file3.php');
?>
To work with multiple hierachical directory levels, maybe you can think of them in term of floor levels such as in a building where you have multiple floors and each floor has rooms--a hotel building comes to mind.
If you are in the third floor and your room is in the fifth floor, you would go up two floors and then once you get to the fifth floor, all you have to do is walk on the flat surface to find your room.
Now if you are in the eighth floor and your room is in the fifth floor, you would go down three floors and then once you get to the fifth floor, all you have to do is walk on the flat surface to find your room.
Now the same thing can be said about multiple directory levels where the current directory is in the third level and you want to find files in the fifth directory deep inside the hierachical directory levels.
Similarly, you would go up two levels using this notation /../../ to be at the same level as the file(s) that you want to find. Once you're at the same level as the file(s) all you have to do is go to get it at the same floor on the flat surface.
Now how about the multiple hierachical directory level of model, view, and controller?
What happens if file7.php or file8.php wants to use either file9.php or file10.php, or both?
Just by looking at the directory structure illustrated earlier, we can see that the grandparent directory of file7.php and file8.php is called 'model' and it is at the same directory level as view and controller--the two directory levels that we're trying to be at.
So now, all we have to do is go up two floors to be at the same level as the parent directory of file9.php and file10.php, or at the same level as view and controller, respectively. The two-floors up (/../../) puts us at the same level as view and controller.
And from there, we can just walk forward directly on the same flat level to the destination. For example:
This is from inside either file7.php or file8.php:
<?php
include (__DIR__ . '/../../view/file9.php');
include (__DIR__ . '/../../controller/file10.php');
include (dirname(__FILE__) . '/../../view/file9.php');
include (dirname(__FILE__) . '/../../controller/file10.php');
?>
Now, what happens if file7.php or file8.php wants to use either file2.php or file4.php, or both?
Again, they have to traverse backward three steps (this time) to be at the same level as the parent directory of file2.php and file4.php, or at the same level as inc and web, respectively. For example:
This is from inside either file7.php or file8.php:
<?php
include (__DIR__ . '/../../../inc/file2.php');
include (__DIR__ . '/../../../web/file4.php');
include (dirname(__FILE__) . '/../../../inc/file2.php');
include (dirname(__FILE__) . '/../../../web/file4.php');
?>
Now, what happens if file7.php or file8.php wants to use index.php?
I'll leave that as an exercise for you to do. This one could be a tricky one!
There you have it! Use __DIR__ instead of dirname(__FILE__) because it is faster and more efficient.
Now let's see what realpath() is all about and how to use it.
realpath() is a function that returns canonicalized absolute pathname in the symbolic links /../../../.
realpath() expands all symbolic links and resolves references to /./, /../ and extra / characters in the input path and returns the canonicalized absolute pathname.
Now take a look at the directory structure example above (again) from the perspective of either file7.php or file8.php. In other words, we're talking from inside either file7.php or file8.php and traversing three levels up to find file9.php or file10.php, respectively: /../../../web/view/, use realpath(/../../../web/view/) to return the canonicalized absolute pathname /web/view/ or /../../../web/controller, use realpath(/../../../web/controller/) to return the canonicalized absolute pathname /web/controller/.
Again, from the perspective of either file7.php or file8.php to find file1.php and file2.php or file3.php and file4.php, respectively: use realpath(/../../../inc/) to return the canonicalized absolute pathname /inc/. Likewise, use realpath(/../../../web/) to return the canonicalized absolute pathname /web/.
Now realpath() on Windows: use realpath('/windows/system32') to return the canonicalized absolute pathname C:\WINDOWS\System32. Likewise, use realpath('C:\Program Files\\') to return the canonicalized absolute pathname C:\Program Files.
There you have it, using realpath() to return the canonicalized absolute pathname: /../../../.
Usage: get_class($this);
Usage: get_called_class ($this);
Usage: __CLASS__;
All three cases achieve the same thing and their usages are identical! So there is no different between them. You can use any one of them and you're good to go.
get_class(), get_called_class(), and __CLASS__ functions all return the name of the actual class which was instantiated. Consider this:
<?php
class ParentClass
{
public function test()
{
echo 'get_called_class() returns: ' . get_called_class() . "\n"; // ChildClass
echo 'get_class() returns: ' . get_class() . "\n"; // ParentClass
echo 'get_class($this) returns: ' . get_class($this) . "\n"; // ChildClass
echo '__CLASS__ returns: ' . __CLASS__ . "\n"; // ParentClass
}
}
class ChildClass extends ParentClass
{
public function testChild()
{
// both return their own immediate class and not the parent class: ParentClass
echo 'get_class() testChild returns: ' . get_class() . "\n"; // ChildClass
echo '__CLASS__ testChild returns: ' . __CLASS__ . "\n"; // ChildClass
}
}
?>
Now let's create another class that uses the ParentClass and ChildClass:
<?php
class Stranger
{
// creating an instance of ChildClass
$instance = new ChildClass();
// here is a test question: what are the answers to this call to test() ?
$instance->test();
/**
* here, class ChildClass is calling ParentClass' method test()
* no, it's not class Stranger that is calling ParentClass' method test()
* in a test, a lot of people seem to think that class Stranger is the current class
* but in this context, it's not the case.
* class Stranger has nothing to do with referencing any of the context.
* it's ChildClass who is calling ParentClass' test() from inside class Stranger.
*
* so get_called_class() returns: ChildClass
* why?
* as the name implies: get the class that calls this method test()
* which is ChildClass who calls ParentClass' method test().
*
* likewise, get_class() as the name implies: get the name of the current class
* which is ParentClass because get_class() was being referenced inside the current
* class ParentClass.
*
* now what happens if get_class() is being referenced inside ChildClass?
* then it would return the current class which is ChildClass.
* if you look inside ChildClass you'll see two examples showing this same
* idea just described.
*
* okay, next we have get_class($this). what is this all about?
* well, passing $this to get_class() tell it to get the class containing in $this.
* in other words, we want to specify which class we want get_class() to return to us.
* in this case, we want get_class() to return a class name that $this is referring to.
*
* we know that $this is referring to the current class object and if you read my
* other tutorial about class verses object, you'll know that both mean the same thing,
* which is a class. so in a sense, $this is a class.
*
* knowing that, get_class($this) returns ChildClass because get_class() was being
* called by the current object $instance which is an object of class ChildClass.
*
* In a test, a lot of people seem to get this wrong quite often because they think
* the current class is the ParentClass and therefore they mark their answer as
* ParentClass.
*
* next, likewise, __CLASS__ returns the current class which is ParentClass because
* __CLASS__ is being referenced inside the current class ParentClass.
*
* well, so too, get_class($this) is being referenced inside the current
* class ParentClass but the difference is the variable $this which is referencing to
* the current 'object' and not the current 'class'.
*/
// here is another test question: what are the output? see the answers below!
$instance->testChild();
}
?>
Now we can see the effect of all six cases:
Output:
get_called_class() returns: ChildClass
get_class() returns: ParentClass
get_class($this) returns: ChildClass
__CLASS__ returns: ParentClass
get_class() testChild returns: ChildClass
__CLASS__ testChild returns: ChildClass
get_called_class() returns the class name that calls test(). In this case, ChildClass calls test().
get_class() returns the class name of itself. get_class() is typically being used inside its own class to return the class name of itself. In this case, it is being used inside test() to return its own class name: ParentClass.
get_class($this) is the same as get_class() above but it specifically specifies which class to return. In this case, it returns the class name of the current class being instantiated. The $this special variable refers to the current object being referenced, in this case, the current object being referenced or instantiated is ChildClass.
__CLASS__ is the same as get_class() and both return the class name of itself. __CLASS__ returns the current class name that __CLASS__ is being referenced in. As you can see in the test() and testChild(), both methods referenced __CLASS__ in its own class that __CLASS__ was residing in.
Like get_class(), __CLASS__ is typically being used inside its own class to return the class name of itself. In this case, it is being used inside test() and testChild() to return their own class name: ParentClass and ChildClass, respectively.
Both __METHOD__ and __FUNCTION__ are special constants (similar to __CLASS__).
__METHOD__ returns the name of the method along with the name of the class that __METHOD__ is being referenced in; while __FUNCTION__ returns only the name of the function that __FUNCTION__ is being referenced in. Consider this:
<?php
class MyClass
{
public function test1()
{
// will output the name of the method along with the name of the class that
// __METHOD__ is being referenced in
echo __METHOD__ . "\n"; // will output: MyClass::test1
}
public function test2()
{
// will output only the name of the function that __FUNCTION__ is being
// referenced in
echo __FUNCTION__ . "\n"; // will output: test2
}
}
?>
And then do this:
$obj = new MyClass();
$obj->test1();
will output ----> MyClass::test1
$obj->test2();
will output -----> test2
FYI: A class is the program you write (i.e., the MyClass class implementation above); while object (i.e., $obj) is the copy of the class or the clone of the class, most often being known as the instance of the class.
A class resides in ROM (permanent memory area) whereas object (i.e., $obj) resides in RAM (temporary memory area.)
In ROM, data is stored there permanently even when the computer is turned off. In a RAM memory area, on the other hand, data get stored temporarily while the program is running or while the computer is still turned on. When the computer is turned off, the RAM data (i.e., $obj) is completely erased and is no longer stored in the RAM.
Instances of a class can be useful only while the program is running or while the computer is turned on; and when the program is not running or when the computer is turned off, instances of a class are no longer useful to a program; and therefore, it is stored in a temporary memory area. Instances of a class can be created 'on the fly' at any time when needed by a program.
So there is no need to store instances of a class permanently in permanent memory spaces and wasting valuable memory spaces.
First of all, it is strongly recommended that you skip the "preface" description outlined next and jump to the abstract and interface descriptions and examples first. After that, once you're finished, then come back and read this "preface" description. That way, you'll understand it much better than reading it right now.
Preface: Abstract verses Interface.
An interface is like a protocol. It doesn't designate the behavior of the object; it designates how your code tells that object to act. An interface would be like the English Language: defining an interface defines how your code communicates with any object implementing that interface. [Say what? If you understood that, you're a genius!]
An interface is always an agreement or a promise. When a class says, "I implement interface Y," it is saying, "I promise to have the same public methods that any object with interface Y has."
On the other hand, an abstract class is like a partially built class. It is much like a document with blanks to fill in. It might be using English, but that isn't as important as the fact that some of the document is already written.
An abstract class is the foundation for another object. When a class says, "I extend abstract class Y," it is saying, "I use some methods or properties already defined in this class named Y."
So, consider the following PHP:
<?php
// this is a child class X implementing an interface Y.
// this is saying that "X" agrees to speak language "Y" with your code.
class X implements Y
{
// code body!
// right here inside this code body that it is saying that
// "X" agrees to speak language "Y" with its "own" X actual code.
// "X" is implementing X's "own" actual code using "Y" language.
}
// this is a child class X extending an abstract parent class Y.
// this is saying that "X" is going to complete the partial class "Y".
class X extends Y
{
// code body!
// right here inside this code body that it is saying that
// "X" agrees to adopt some of the "Y" declarations (or language)
// and even uses Y's actual implementation in the case of static methods.
}
?>
As you can see, you might already noticed the difference: an interface uses the keyword: implements while an abstract uses the keyword: extends.
You would have your class implements a particular interface if you were distributing a class to be used by other people. The interface is an agreement to have a specific set of public methods for your class.
You would have your class extends an abstract class if you (or someone else) wrote a class that already had some methods written (or fully implemented inside parent class) that you want to use in your new (child) class or classes.
These two concepts, while easy to confuse, are specifically different and distinct. For all intents and purposes, if you're the only user of any of your classes, you don't need to implement interfaces. You would use abstracts.
[End "preface" description.]
An abstract, as the word implies, is a plain concept existing in thought or as an idea only and not having a physical or concrete existence. It exists in thought or idea only without any physical existence.
An abstract idea is an idea that haven't been put into concrete physical ready-made product yet. It exists in idea or thought only and haven't been made as a product yet.
Spriritual belief is an abstract idea because it exists in thought only and not having a concrete existence. Instinct is an abstract idea because it exists in thought only and not having a concrete existence.
Having a killer instinct is an abstract idea because it exists in thought only and not having a concrete existence.
Having a fantasy on something is an abstract idea because it exists in thought only and not having a concrete existence.
To sum it all up: All forms of idea are abstract ideas because it exists in thought only and not having a concrete existence.
In programming, an abstract class is a class that haven't been implemented yet. It exists only in the declaration of the class only. It hasn't been implemented in actual code yet.
In a class declaration, it contains the keyword abstract, followed by the keyword class, followed by the class' name.
It also contains the un-implemented body as well, for example: the class properties, followed by the class' methods (also known as functions).
That's all! No specific code is implemented in the class body itself and no specific code is implemented in the methods of the class either.
An abstract class is a class that can contain properties. Properties are optional. However, an abstract class must contain at least one abstract method.
An abstract method is a method that is declared in the abstract class, but have not been implemented in the actual code just yet [inside the abstract class itself]. So basically, an abstract class just declares its properties and methods without implementing any actual code.
The implementation of the actual code is left for the child classes to implement their own distinct seperate ways. The key phrase fragment is: 'own distinct seperate ways' because each implementation of the actual code is unique to each child class' implementation.
That's why it is called 'abstract' class and 'abstract' method because the class and the methods are very abstract without any implementation.
Let's examine and clarify this phrase a little bit: an 'abstract class just declares its properties and methods without implementing any actual code.'
Don't let that phrase fools you: an abstract class can declare its properties and methods AND implementing any actual code as well -- if need to!
Yes, you can declare an abstract class with its properties and methods and as well as fully-implementing any actual code as well! This is perfectly very legal!
However, generally an abstract class just declares its properties and methods without implementing any actual code and leave all the implementation to its child classes. That's the usual way of doing it; however, nothing stops you from implementing actual code in abstract classes.
As a matter of fact, a lot of programmers do just that: they create their abstract classes with their properties and methods fully-implemented with any actual code that they need to.
So nothing stops you from doing that either!!!
You typically declare static properties and methods of abstract class as you normally would and then, fully-implementing any actual code if you need to, including an abstract class's constructor . For example:
<?php
abstract class MyClass extends MyParentClass
{
/**
* declaring abstract class' constants and fully-implementing them as well
* by initializing their values. there is nothing wrong with that!
*/
const EVENT_COMMAND_START = 'command_start';
const STATE_BEGIN = 0;
/**
* declaring abstract class' properties without initialization with their
* initial values. this is the usual way of doing!
*/
protected static $conn;
public $databaseName;
public $username;
public $password;
public function __construct($databaseName, $username, $password)
{
/**
* this is not the secure way of doing - passing connection data in
* the constructor. you should do a better/secure way than this!
* besides, this is not about security - it's about abstract programming!
*/
$this->databaseName = $databaseName;
$this->username = $username;
$this->password = $password;
$this->getConnection();
// more constructor code!
}
static function getConnection()
{
self::$conn = new PDO("mysql:host=$host;dbname=$this->databaseName",
"$this->username", "$this->password");
}
static function test()
{
echo "test\n";
}
}
?>
As you can see, nothing stops you from implementing your abstract classes, if you need to. This is especially true with static methods because you can invoke them statically as shown in the below example in abstract class Foo. For example:
<?php
abstract class Foo
{
static function bar()
{
echo "test bar\n";
}
}
?>
Now you can reference the static method bar like this: Foo::bar(); // output: 'test bar'
Or for the abstract class MyClass shown earlier:
Likewise, you can reference the static method test like this: MyClass::test(); // output: 'test'
And for the static method getConnection like this: MyClass::getConnection(); // return: 'a PDO connection object'
You are allowed to do this only with static methods.
All non-static methods are better left to child classes to implement them.
All child classes that extend from the parent abstract class must implement all of the abstract methods that the parent class has. Let's see some examples.
An abstract class or method is defined with the abstract keyword. For example:
<?php
abstract class ParentClass
{
abstract public function someMethodName1()
abstract public function someMethodName2($name, $color);
abstract public function someMethodName3() : string;
abstract public function someMethodName4() : [];
abstract public function someMethodName5() : array();
}
?>
There you have it! An abstract class called ParentClass.
As you can see, there is no specific implementation of the class body itself, including the five methods, except static methods [e.g., you can declare your static methods among your non-static methods and at the same time fully-implementing them - nothing stops you from doing that].
It just declares them and leave them for the child classes to implement them in their own unique ways. Now any class or classes can inherit from this abstract parent class and implement the functionalities any way according to their objective.
Just remember that all child classes that extend from the abstract (parent) class [like ParentClass above] must implement all of the abstract methods contained in the parent class [like the five methods shown in the ParentClass above].
ParentClass above) cannot be instantiated. But child classes that extends from an abstract parent class can be instantiated.
This only means that you cannot instantiate and initialize an object from an abstract class declared like the one shown above. And as a result of the fact that you cannot instantiate and initialize an object from an abstract class, you cannot also call or reference any properties or methods of the abstract class.
In order to be able to call or reference any properties or methods of the abstract class, you have to do it by referring to its child classes. So in effect, you're just calling or referencing the properties and methods of the child classes.
However, invoking static method of abstract class is still feasible as you've seen in the classes Foo and ParentClass examples above. Make note: Only static methods of the abstract class can be called or referenced directly without having to derive a child class.
When inheriting from an abstract class, all methods marked as abstract in the parent's class declaration must be defined or implemented by the child. When inheriting from an abstract class, the child class method must be defined or implemented with the same name, and the same or a less restricted access modifier.
So, if the abstract method is defined as protected, the child class method must be defined as either protected or public, but not private. Also, the type and number of required arguments must be the same. However, the child classes may have optional arguments in addition.
For example:
<?php
abstract class ParentClass
{
abstract public function someMethodName($name, $color);
}
?>
Now we can define our child class with additional arguments. Additional arguments must go after the list of parent arguments. For example:
<?php
class ChildClass extends ParentClass
{
// our child class may define optional additional arguments not defined in the
// parent's signature
public function someMethodName($name, $color, $size, $make, $model);
}
?>
As you can see, when a child class is inherited from an abstract parent class, the abstract keyword goes away from the class head declaration and from the method heading as well. They're real class and real method now and no longer abstract.
So, when a child class is inherited from an abstract class, we have the following rules:
method must be defined with the same name (i.e., someMethodName()) and it redeclares the parent abstractt method. In other words, it must be the same signature declaration as the parent method declaration (in the above case, someMethodName($name, $color).method must be defined with the same or a less restricted access modifier (in the above case, public).
So, if the abstract method is defined as protected, the child class method must be defined as either protected or public, but not private.
Let's look at an example:
<?php
abstract class SpaceShip extends Event
{
private $radar = [];
private $fuel = int;
private $camera = array();
private $command = string;
abstract public function Start($start);
abstract public function goUp($up);
abstract public function goDown($down);
abstract public function goLeft($left);
abstract public function goRight($right);
abstract public function Speedometer($speed);
abstract public function Throttle($gear);
}
?>
Okay, we're building an abstract 'Spaceship' vehicle class that individuals or countries that want to go to Mars can use this abstract class to implement their own unique Mars spaceship vehicle. Any individual or country that implements this abstract class 'Spaceship' must implement all of the methods provided here.
Of course, they can add more functionalities in their own class as well, but the basic functionalities to go to Mars is provided here in this base abstract class 'Spaceship'.
Now in their own unique implementation, they can do a lot more to make their spaceship vehicle functional that can reach their destination safely, which is Mars.
Disclaimer: I'm not an expert in Mars spaceship vehicle or any spaceship vehicle, or any non-spaceship vehicle for that matter.
With that disclaimer taken care of, let's proceed to see how one would go about in implementing a Mars spaceship vehicle command interface software.
<?php
class Mars extends SpaceShip
{
const COMMAND_EVENT_START = 'command_start';
const COMMAND_EVENT_UP = 'command_up';
const COMMAND_EVENT_DOWN = 'command_down';
const COMMAND_EVENT_LEFT = 'command_left';
const COMMAND_EVENT_RIGHT = 'command_right';
const COMMAND_EVENT_SPEED = 'command_speed';
const COMMAND_EVENT_THROTTLE = 'command_throttle';
public $radar = [];
public $fuel = int;
public $camera = array();
public $command = string;
public $start = 0;
public $speed = 0;
public $up = 0;
public $down = 0;
public $left = 0;
public $right = 0;
public $gear = 0;
public function __construct($speed, $up, $down, $left, $right, $gear)
{
// initialize the spaceship object. in other words, ground the spaceship!
$this->start = component::start();
$this->speed = $speed;
$this->up = $up;
$this->down = $down;
$this->left = $left;
$this->right = $right;
$this->gear = $gear;
// attach an event to ignite the space ship vehicle
$this->event(self::COMMAND_EVENT_START, [$this, 'Start'], $this->start);
// attach an event to increase/decrease the speed of the space ship vehicle
$this->event(self::COMMAND_EVENT_SPEED, [$this, 'Speedometer'], $this->speed);
// attach an event to go up in altitude
$this->event(self::COMMAND_EVENT_UP, [$this, 'goUp'], $this->up);
// attach an event to go down in altitude
$this->event(self::COMMAND_EVENT_DOWN, [$this, 'goDown'], $this->down);
// attach an event to turn left
$this->event(self::COMMAND_EVENT_LEFT, [$this, 'goLeft'], $this->left);
// attach an event to turn right
$this->event(self::COMMAND_EVENT_RIGHT, [$this, 'goRight'], $this->right);
// attach an event to throttle the speed of the space ship vehicle
$this->event(self::COMMAND_EVENT_THROTTLE, [$this, 'Throttle'], $this->gear);
}
public function Start($event)
{
// this function is called by the IgnitionController as a result of the
// event mechanism.
// the event mechanism is implemented in the Event class that class SpaceShip
// extends from.
// likewise, the component class is implemented as a component in which
// the Event class extends from it.
// the Event class, in turn, implements the IEvent interface class.
// however, all of the work is being done in the Event class.
// right here where you fire up the ignition
component::start($event->data);
}
public function Speedometer($event)
{
// right here where you increase/decrease the speed of the vehicle
component::speed($event->data);
}
public function goUp($event)
{
// right here where you go up in altitude
component::up($event->data);
}
public function goDown($event)
{
// right here where you go down in altitude
component::down($event->data);
}
public function goLeft($event)
{
// right here where you tell the space ship vehicle to turn left
component::left($event->data);
}
public function goRight($event)
{
// right here where you tell the space ship vehicle to turn right
component::right($event->data);
}
public function Throttle($event)
{
// un-implemented);
}
}
?>
As you can see, it is very easy to do abstract programming and it is a very powerful methodology that allows you to modularize your program.
Of course, you can have additional properties and methods as well [in addition to the inherited methods].
Guess what? It's legal to leave the methods un-implemented [as shown in the Throttle() above] as long as they're declared and included in the child class' code body as shown above.
Of course, the Mars space ship class is going nowhere as it stands right now. But that is not the point of this tutorial. The goal of this tutorial is to teach you how to do abstract programming and the example shown thus far should help you understand how to do abstract programming.
Alright, we'll build one to go to the moon as well.
<?php
class Moon extends SpaceShip
{
const COMMAND_EVENT_UP = 'command_up';
const COMMAND_EVENT_DOWN = 'command_down';
const COMMAND_EVENT_LEFT = 'command_left';
const COMMAND_EVENT_RIGHT = 'command_right';
const COMMAND_EVENT_SPEED = 'command_speed';
const COMMAND_EVENT_THROTTLE = 'command_throttle';
public $radar = [];
public $fuel = int;
public $camera = array();
public $command = string;
public $speed = 0;
public $up = 0;
public $down = 0;
public $left = 0;
public $right = 0;
public $gear = 0;
public function __construct($speed, $up, $down, $left, $right, $gear)
{
// initialize the spaceship object. in other words, ground the spaceship!
$this->speed = $speed;
$this->up = $up;
$this->down = $down;
$this->left = $left;
$this->right = $right;
$this->gear = $gear;
// attach an event to ignite the space ship vehicle
$this->event(self::COMMAND_EVENT_START, [$this, 'Start'], $this->start);
// attach an event to increase/decrease the speed of the space ship vehicle
$this->event(self::COMMAND_EVENT_SPEED, [$this, 'Speedometer'], $this->speed);
// attach an event to go up in altitude
$this->event(self::COMMAND_EVENT_UP, [$this, 'goUp'], $this->up);
// attach an event to go down in altitude
$this->event(self::COMMAND_EVENT_DOWN, [$this, 'goDown'], $this->down);
// attach an event to turn left
$this->event(self::COMMAND_EVENT_LEFT, [$this, 'goLeft'], $this->left);
// attach an event to turn right
$this->event(self::COMMAND_EVENT_RIGHT, [$this, 'goRight'], $this->right);
// attach an event to throttle the speed of the space ship vehicle
$this->event(self::COMMAND_EVENT_THROTTLE, [$this, 'Throttle'], $this->gear);
}
public function Start($event)
{
// this function is called by the IgnitionController as a result of the
// event mechanism.
// the event mechanism is implemented in the Event class that class SpaceShip
// extends from.
// likewise, the component class is implemented as a component in which
// the Event class extends from it.
// the Event class, in turn, implements the IEvent interface class.
// however, all of the work is being done in the Event class.
// right here where you fire up the ignition
component::start($event->data);
}
public function Speedometer($event)
{
// right here where you increase/decrease the speed of the vehicle
component::speed($event->data);
}
public function goUp($event)
{
// right here where you go up in altitude
component::up($event->data);
}
public function goDown($event)
{
// right here where you go down in altitude
component::down($event->data);
}
public function goLeft($event)
{
// right here where you tell the space ship vehicle to turn left
component::left($event->data);
}
public function goRight($event)
{
// right here where you tell the space ship vehicle to turn right
component::right($event->data);
}
public function Throttle($event)
{
// right here where you tell the space ship vehicle to throttle the speed
component::gear($event->data);
}
}
?>
Okay, we'll build one to go to the Jupiter as well.
<?php
class Jupiter extends SpaceShip
{
const COMMAND_EVENT_UP = 'command_up';
const COMMAND_EVENT_DOWN = 'command_down';
const COMMAND_EVENT_LEFT = 'command_left';
const COMMAND_EVENT_RIGHT = 'command_right';
const COMMAND_EVENT_SPEED = 'command_speed';
const COMMAND_EVENT_THROTTLE = 'command_throttle';
public $radar = [];
public $fuel = int;
public $camera = array();
public $command = string;
public $speed = 0;
public $up = 0;
public $down = 0;
public $left = 0;
public $right = 0;
public $gear = 0;
public function __construct($speed, $up, $down, $left, $right, $gear)
{
// initialize the spaceship object. in other words, ground the spaceship!
$this->speed = $speed;
$this->up = $up;
$this->down = $down;
$this->left = $left;
$this->right = $right;
$this->gear = $gear;
// attach an event to ignite the space ship vehicle
$this->event(self::COMMAND_EVENT_START, [$this, 'Start'], $this->start);
// attach an event to increase/decrease the speed of the space ship vehicle
$this->event(self::COMMAND_EVENT_SPEED, [$this, 'Speedometer'], $this->speed);
// attach an event to go up in altitude
$this->event(self::COMMAND_EVENT_UP, [$this, 'goUp'], $this->up);
// attach an event to go down in altitude
$this->event(self::COMMAND_EVENT_DOWN, [$this, 'goDown'], $this->down);
// attach an event to turn left
$this->event(self::COMMAND_EVENT_LEFT, [$this, 'goLeft'], $this->left);
// attach an event to turn right
$this->event(self::COMMAND_EVENT_RIGHT, [$this, 'goRight'], $this->right);
// attach an event to throttle the speed of the space ship vehicle
$this->event(self::COMMAND_EVENT_THROTTLE, [$this, 'Throttle'], $this->gear);
}
public function Start($event)
{
// this function is called by the IgnitionController as a result of the
// event mechanism.
// the event mechanism is implemented in the Event class that class SpaceShip
// extends from.
// likewise, the component class is implemented as a component in which
// the Event class extends from it.
// the Event class, in turn, implements the IEvent interface class.
// however, all of the work is being done in the Event class.
// right here where you fire up the ignition
component::start($event->data);
}
public function Speedometer($event)
{
// right here where you increase/decrease the speed of the vehicle
component::speed($event->data);
}
public function goUp($event)
{
// right here where you go up in altitude
component::up($event->data);
}
public function goDown($event)
{
// right here where you go down in altitude
component::down($event->data);
}
public function goLeft($event)
{
// right here where you tell the space ship vehicle to turn left
component::left($event->data);
}
public function goRight($event)
{
// right here where you tell the space ship vehicle to turn right
component::right($event->data);
}
public function Throttle($event)
{
// right here where you tell the space ship vehicle to throttle the speed
component::gear($event->data);
}
}
?>
To launch the spaceship we need several controller classes [in an MVC scheme of thing].
Firstly, we need one controller for the ignition controller. This is very important because we have to fire up an ignition remotely if we have to in case the space ship is stalled in the middle of nowhere.
For takeoff we need another controller class as well. Again, we can tell the space ship to takeoff remotely if we need to.
So basically, we need one controller per task that the space ship is undertaking. For example, one controller to tell the space ship to speed up or decrease the speed; one controller to go up in altitude; another controller to go down in altitude; another controller to turn left; another controller to turn right, and so on and so forth.
For this tutorial, we won't implement all of the controller but only implementing a couple of controller, leaving the rest as exercises for you to do. Here is the ingition controller:
<?php
class IgnitionController extends Controller
{
public function ignitionEvent()
{
// first, create an instance of our Mars class
$launch = new Mars();
// to start the engine, press the "start" button on the spaceship dashboard or
// remotely in a dashboard remote device
// the effect of pressing the "start" button will propagate to the
// IgnitionController class and executes the ignitionEvent() right here!
// in here where we trigger the "command-start" event to fire up the ignition.
// In other words, trigger() executes the callback function Start() [of the class
// Mars], in which, Start() is attached to the event constant COMMAND_EVENT_START.
// if you look in the Mars' constructor you'll see some statements like this:
// $this->event(self::COMMAND_EVENT_START, [$this, 'Start'], $this->start).
// the 'Start' in [$this, 'Start'] is the callback function name
// that gets called when the below statement is triggered/executed.
// notice that method trigger() is implemented in the class Event.
// class Event is not included here!
// the Event class implements the IEvent interface class.
// however, all of the work is being done in the Event class.
// that's all there is! this one line kickstarts the ignition!
$launch->trigger(Mars::COMMAND_EVENT_START);
}
}
?>
Here is the SpeedController:
<?php
class SpeedController extends Controller
{
public function speedEvent()
{
// first, create an instance of our Mars class
$launch = new Mars();
// to increase/decrease the speed, press the "+" or "-" button next to
// "speed" label on the spaceship dashboard or remotely via a
// dashboard remote device.
// the effect of pressing the "+" or "-" button will propagate to this
// SpeedController class here and therefore executes this speedEvent() in here!
// similar to the ignitionEvent() above, this trigger() executes the callback
// function Speedometer() which is attached to the event constant:
// COMMAND_EVENT_SPEED.
// if you look in the Mars' constructor you'll see some statements like this:
// $this->event(self::COMMAND_EVENT_SPEED, [$this, 'Speedometer'], $this->speed).
// the 'Speedometer' in [$this, 'Speedometer'] is the callback function
// name that gets called when the below statement is triggered/executed.
// notice also that we can trigger the event using the event name 'command_speed'
$launch->trigger('command_speed');
}
}
?>
The rest of the controller are implemented in similar fashion.
Here are some more abstract concept code examples:
<?php
abstract class BankAccount
{
// hold the current balance for the account
public $balance = 0;
// increase the current balance for the account
abstract public function Debit($acctNo, $amount);
// decrease the current balance for the account
abstract public function Credit($acctNo, $amount);
// return the current balance for the account
abstract public function getBalance($acctNo);
}
?>
Here is the child class CheckingAccount code example:
<?php
protected class CheckingAccount extends BankAccount
{
// deposit/increase the current balance for the account
public function Debit($acctNo, $amount);
{
// first authenticate the account holder.
// you should do a better authentication here! you get the point!
if ($acctNo == '12345';
{
$this->balance = $this->balance + $amount;
}
else
{
echo "Account access denied!";
}
}
// withdraw/decrease the current balance for the account
public function Credit($acctNo, $amount);
{
// first authenticate the account holder.
// you should do a better authentication here! you get the point!
if ($acctNo == '12345';
{
$this->balance = $this->balance - $amount;
}
else
{
echo "Account access denied!";
}
}
// get the current balance for the account
public function getBalance($acctNo);
{
// first authenticate the account holder.
// you should do a better authentication here! you get the point!
if ($acctNo == '12345';
{
return $this->balance;
}
else
{
echo "Account access denied!";
}
}
} // end CheckingAccount
?>
Here is the child class SavingsAccount code example:
<?php
protected class SavingsAccount extends BankAccount
{
// deposit/increase the current balance for the account
public function Debit($acctNo, $amount);
{
// first authenticate the account holder.
// you should do a better authentication here! you get the point!
if ($acctNo == '12345';
{
$this->balance = $this->balance + $amount;
}
else
{
echo "Account access denied!";
}
}
// withdraw/decrease the current balance for the account
public function Credit($acctNo, $amount);
{
// first authenticate the account holder.
// you should do a better authentication here! you get the point!
if ($acctNo == '12345';
{
$this->balance = $this->balance - $amount;
}
else
{
echo "Account access denied!";
}
}
// get the current balance for the account
public function getBalance($acctNo);
{
// first authenticate the account holder.
// you should do a better authentication here! you get the point!
if ($acctNo == '12345';
{
return $this->balance;
}
else
{
echo "Account access denied!";
}
}
} // end SavingsAccount
?>
Here is the child class PreferredSavingsAccount code example:
<?php
protected class PreferredSavingsAccount extends BankAccount
{
// deposit/increase the current balance for the account
public function Debit($acctNo, $amount);
{
// first authenticate the account holder.
// you should do a better authentication here! you get the point!
if ($acctNo == '12345';
{
$this->balance = $this->balance + $amount;
}
else
{
echo "Account access denied!";
}
}
// withdraw/decrease the current balance for the account
public function Credit($acctNo, $amount);
{
// first authenticate the account holder.
// you should do a better authentication here! you get the point!
if ($acctNo == '12345';
{
$this->balance = $this->balance - $amount;
}
else
{
echo "Account access denied!";
}
}
// get the current balance for the account
public function getBalance($acctNo);
{
// first authenticate the account holder.
// you should do a better authentication here! you get the point!
if ($acctNo == '12345';
{
return $this->balance;
}
else
{
echo "Account access denied!";
}
}
} // end PreferredSavingsAccount
?>
Here is the child class CreditCardAccount code example:
<?php
protected class CreditCardAccount extends BankAccount
{
// deposit/increase the current balance for the account
public function Debit($acctNo, $amount);
{
// first authenticate the account holder.
// you should do a better authentication here! you get the point!
if ($acctNo == '12345';
{
$this->balance = $this->balance + $amount;
}
else
{
echo "Account access denied!";
}
}
// withdraw/decrease the current balance for the account
public function Credit($acctNo, $amount);
{
// first authenticate the account holder.
// you should do a better authentication here! you get the point!
if ($acctNo == '12345';
{
$this->balance = $this->balance - $amount;
}
else
{
echo "Account access denied!";
}
}
// get the current balance for the account
public function getBalance($acctNo);
{
// first authenticate the account holder.
// you should do a better authentication here! you get the point!
if ($acctNo == '12345';
{
return $this->balance;
}
else
{
echo "Account access denied!";
}
}
} // end CreditCardAccount
?>
Next up is an interface programming tutorial. An interface programming is similar to an abstract programming.
What is an Interface?
An interface is essentially a blueprint or a contract or a promise or a protocol or a guideline for what you can create.
For example, an interface declares five methods. These five methods are the blueprint or the contract or the promise or the protocol or the guideline for what child classes can create/implement based on these five methods. If a child class wants to implement this interface it must implement all five methods that the interface has.
The five methods act as a blueprint or a contract or a promise or a protocol or a guideline for what child classes can create/implement.
An interface allows unrelated child classes to implement the same set of methods (i.e., the five methods mentioned above), regardless of their positions in the class inheritance hierarchy. If you've read the Mars spaceship example earlier, there were seven methods declared for the abstract parent class SpaceShip.
We could just as well swap that abstract class with an interface instead, making that abstract class as an interface having seven methods being declared as the interface parent class ISpaceShip.
Now any class that wants to use the interface ISpaceShip must implement the seven methods declared in the interface parent class ISpaceShip.
Here is the interface parent class ISpaceShip:
<?php
// like a class, you can extend an interface from another interface using
// the 'extends' operator: interface ISpaceShip extends IEvent
interface ISpaceShip extends IEvent
{
// this means that child classes that implement interface ISpaceShip have to implement
// all of the methods declared in all of the parent interfaces: ISpaceShip, IEvent
// note that if you don't want to do any actual code implementation in any of the child
// methods, you can just list the (required interface) methods in the child class
// definition without their actual code implentation! just empty methods! it is legal!
// however, doing that defeats the purpose of child classes implementing parent interfaces!
// An interface consists of methods that contain no implementation.
// In other words, all methods of the interface are abstract methods just like
// the abstract class SpaceShip declared earlier.
// An interface can have its own constants, as the following shows:
const COMMAND_EVENT_UP = 'command_up';
const COMMAND_EVENT_DOWN = 'command_down';
const COMMAND_EVENT_LEFT = 'command_left';
const COMMAND_EVENT_RIGHT = 'command_right';
const COMMAND_EVENT_SPEED = 'command_speed';
const COMMAND_EVENT_THROTTLE = 'command_throttle';
// An interface cannot contain properties.
// The following four statements are illegal!
// You cannot have these. These have to be declared in the child classes.
// There you have it:
// if you want to know the difference between abstract and interface
// This is one of the differences between abstract and interface
private $radar = [];
private $fuel = int;
private $camera = array();
private $command = string;
// The following statements are legal!
public function Start($start);
public function goUp($up);
public function goDown($down);
public function goLeft($left);
public function goRight($right);
public function Speedometer($speed);
public function Throttle($gear);
}
?>
Unlike a class, which can extend only from one (other) class, an interface can extend from multiple interfaces, making the class that implements the interface as a multi-inheritance functionality class.
Here is an abbreviated listing of IEvent that extends two interfaces:
<?php
// an interface can extend from multiple interfaces using the 'extends' operator
// and seperating each interface with a comma.
interface IEvent extends IBase, IObject
{
// An interface cannot contain property/attribute declarations -- no properties!.
// An interface consists of method declarations that contain no implementation.
public function event($class, $name, $handler, $data, $append = true);
// An interface consists of method declarations that contain no implementation.
public function trigger($class, $name, $event = null);
}
// this means that child classes have to implement all of the methods
// declared in all of the parent interfaces: IEvent, IBase, IObject
/**
* Usage:
*
* notice that ISpaceShip extends IEvent and therefore class Event
* gets access to IEvent through parent class ISpaceShip
*
* class Event implements ISpaceShip
* {
* // code body
* }
*
* or you can implement IEvent directly as well:
*
* class Event implements IEvent
* {
* // code body
* }
*/
?>
A class can only extend from one (other) class; however, an interface can inherit multiple inheritances from other interfaces. In other words, interfaces allow classes to inherit multiple inheritances through the use of the interfaces.
A class can implement multiple interfaces, making the class as a multi-inheritance functionality class.
Here is an abbreviated listing of IComponent that extends three interfaces:
<?php
interface IComponent extends IBase, ICore, IObject
{
public function setComponent($name, $value);
public function getComponent($name);
}
?>
When we want to declare a new class that reuses properties and methods of an existing class, we say a subclass inherits from or extends a parent class. However, for the interfaces, we say a class implements an interface.
A class can only inherit from one parent class, but in addition, a class can implement one or more interfaces (in the case below: a class Moon extends the abstract SpaceShip parent class and as well as implements the ISpaceShip and IComponent interfaces). For example:
<?php
// notice that class Moon first extends from an abstract class SpaceShip which was
// defined earlier in the abstract programming section, and then, it implements
// two interfaces: ISpaceShip and IComponent
// yes, this is the order: you first extend the class and then implement the interfaces.
class Moon extends SpaceShip implements ISpaceShip, IComponent
{
const COMMAND_EVENT_UP = 'command_up';
const COMMAND_EVENT_DOWN = 'command_down';
const COMMAND_EVENT_LEFT = 'command_left';
const COMMAND_EVENT_RIGHT = 'command_right';
const COMMAND_EVENT_SPEED = 'command_speed';
const COMMAND_EVENT_THROTTLE = 'command_throttle';
public $radar = [];
public $fuel = int;
public $camera = array();
public $command = string;
public $speed = 0;
public $up = 0;
public $down = 0;
public $left = 0;
public $right = 0;
public $gear = 0;
public function __construct($speed, $up, $down, $left, $right, $gear)
{
// initialize the spaceship object. in other words, ground the spaceship!
$this->speed = $speed;
$this->up = $up;
$this->down = $down;
$this->left = $left;
$this->right = $right;
$this->gear = $gear;
// attach an event to ignite the space ship vehicle
$this->event(self::COMMAND_EVENT_START, [$this, 'Start'], $this->start);
// attach an event to increase/decrease the speed of the space ship vehicle
$this->event(self::COMMAND_EVENT_SPEED, [$this, 'Speedometer'], $this->speed);
// attach an event to go up in altitude
$this->event(self::COMMAND_EVENT_UP, [$this, 'goUp'], $this->up);
// attach an event to go down in altitude
$this->event(self::COMMAND_EVENT_DOWN, [$this, 'goDown'], $this->down);
// attach an event to turn left
$this->event(self::COMMAND_EVENT_LEFT, [$this, 'goLeft'], $this->left);
// attach an event to turn right
$this->event(self::COMMAND_EVENT_RIGHT, [$this, 'goRight'], $this->right);
// attach an event to throttle the speed of the space ship vehicle
$this->event(self::COMMAND_EVENT_THROTTLE, [$this, 'Throttle'], $this->gear);
}
public function Start($event)
{
// this function is called by the IgnitionController as a result of the
// event mechanism.
// the event mechanism is implemented in the Event class that class SpaceShip
// extends from.
// likewise, the component class is implemented as a component in which
// the Event class extends from it.
// right here where you fire up the ignition
component::start($event->data);
}
public function Speedometer($event)
{
// right here where you increase/decrease the speed of the vehicle
component::speed($event->data);
}
public function goUp($event)
{
// right here where you go up in altitude
component::up($event->data);
}
public function goDown($event)
{
// right here where you go down in altitude
component::down($event->data);
}
public function goLeft($event)
{
// right here where you tell the space ship vehicle to turn left
component::left($event->data);
}
public function goRight($event)
{
// right here where you tell the space ship vehicle to turn right
component::right($event->data);
}
public function Throttle($event)
{
// right here where you tell the space ship vehicle to throttle the speed
component::gear($event->data);
}
// these interface methods need to be implemented!!!
public function event($class, $name, $handler, $data, $append = true)
{
// this interface method needs to be implemented!!!
}
public function trigger($class, $name, $event = null)
{
// this interface method needs to be implemented!!!
}
public function setComponent($name, $value)
{
// this interface method needs to be implemented!!!
}
public function getComponent($name)
{
// this interface method needs to be implemented!!!
}
}
?>
Here are some more interface concept code examples:
<?php
interface IBankAccount
{
// increase the current balance for the account
abstract public function Debit($acctNo, $amount);
// decrease the current balance for the account
abstract public function Credit($acctNo, $amount);
// return the current balance for the account
abstract public function getBalance($acctNo);
}
?>
Here is the child class CheckingAccount code example:
<?php
protected class CheckingAccount implements IBankAccount
{
// an interface cannot contain properties, so they will have to
// be declared in the child classes like what we're doing right here!
// hold the current balance for the account
public $balance = 0;
// deposit/increase the current balance for the account
public function Debit($acctNo, $amount);
{
// first authenticate the account holder.
// you should do a better authentication here! you get the point!
if ($acctNo == '12345';
{
$this->balance = $this->balance + $amount;
}
else
{
echo "Account access denied!";
}
}
// withdraw/decrease the current balance for the account
public function Credit($acctNo, $amount);
{
// first authenticate the account holder.
// you should do a better authentication here! you get the point!
if ($acctNo == '12345';
{
$this->balance = $this->balance - $amount;
}
else
{
echo "Account access denied!";
}
}
// get the current balance for the account
public function getBalance($acctNo);
{
// first authenticate the account holder.
// you should do a better authentication here! you get the point!
if ($acctNo == '12345';
{
return $this->balance;
}
else
{
echo "Account access denied!";
}
}
} // end CheckingAccount
?>
Here is the child class SavingsAccount code example:
<?php
protected class SavingsAccount implements IBankAccount
{
// an interface cannot contain properties, so they will have to
// be declared in the child classes like what we're doing right here!
// hold the current balance for the account
public $balance = 0;
// deposit/increase the current balance for the account
public function Debit($acctNo, $amount);
{
// first authenticate the account holder.
// you should do a better authentication here! you get the point!
if ($acctNo == '12345';
{
$this->balance = $this->balance + $amount;
}
else
{
echo "Account access denied!";
}
}
// withdraw/decrease the current balance for the account
public function Credit($acctNo, $amount);
{
// first authenticate the account holder.
// you should do a better authentication here! you get the point!
if ($acctNo == '12345';
{
$this->balance = $this->balance - $amount;
}
else
{
echo "Account access denied!";
}
}
// get the current balance for the account
public function getBalance($acctNo);
{
// first authenticate the account holder.
// you should do a better authentication here! you get the point!
if ($acctNo == '12345';
{
return $this->balance;
}
else
{
echo "Account access denied!";
}
}
} // end SavingsAccount
?>
Here is the child class PreferredSavingsAccount code example:
<?php
protected class PreferredSavingsAccount implements IBankAccount
{
// an interface cannot contain properties, so they will have to
// be declared in the child classes like what we're doing right here!
// hold the current balance for the account
public $balance = 0;
// deposit/increase the current balance for the account
public function Debit($acctNo, $amount);
{
// first authenticate the account holder.
// you should do a better authentication here! you get the point!
if ($acctNo == '12345';
{
$this->balance = $this->balance + $amount;
}
else
{
echo "Account access denied!";
}
}
// withdraw/decrease the current balance for the account
public function Credit($acctNo, $amount);
{
// first authenticate the account holder.
// you should do a better authentication here! you get the point!
if ($acctNo == '12345';
{
$this->balance = $this->balance - $amount;
}
else
{
echo "Account access denied!";
}
}
// get the current balance for the account
public function getBalance($acctNo);
{
// first authenticate the account holder.
// you should do a better authentication here! you get the point!
if ($acctNo == '12345';
{
return $this->balance;
}
else
{
echo "Account access denied!";
}
}
} // end PreferredSavingsAccount
?>
Here is the child class CreditCardAccount code example:
<?php
protected class CreditCardAccount implements IBankAccount
{
// an interface cannot contain properties, so they will have to
// be declared in the child classes like what we're doing right here!
// hold the current balance for the account
public $balance = 0;
// deposit/increase the current balance for the account
public function Debit($acctNo, $amount);
{
// first authenticate the account holder.
// you should do a better authentication here! you get the point!
if ($acctNo == '12345';
{
$this->balance = $this->balance + $amount;
}
else
{
echo "Account access denied!";
}
}
// withdraw/decrease the current balance for the account
public function Credit($acctNo, $amount);
{
// first authenticate the account holder.
// you should do a better authentication here! you get the point!
if ($acctNo == '12345';
{
$this->balance = $this->balance - $amount;
}
else
{
echo "Account access denied!";
}
}
// get the current balance for the account
public function getBalance($acctNo);
{
// first authenticate the account holder.
// you should do a better authentication here! you get the point!
if ($acctNo == '12345';
{
return $this->balance;
}
else
{
echo "Account access denied!";
}
}
} // end CreditCardAccount
?>
The Rule
The methods have to go in only in one child class. Classes may implement more than one interface if desired by separating each interface with a comma.
Why should we use PHP interfaces?
There are several reasons that we should use interface in our PHP object-oriented programming:
WHEN SHOULD YOU MAKE A CLASS AND WHEN SHOULD YOU MAKE AN INTEFACE?
If you have a class that is never directly instantiated in your program, this is a good candidate for an interface. In other words, if you are creating a class to only serve as the parent to other classes, it should probably be made into an interface.
When you know what methods a class should have but you are not sure what the details will be. When you want to quickly map out the basic structures of your classes to serve as a template for others to follow -- keeps the code-base predictable and consistent -- it should probably be made into an interface..
A vararg is a variable-length argument list (a.k.a. vararg, variadic arguments), using the ellipsis (three dots, ...) token before the argument name to indicate that the parameter is variadic, i.e., it is an array variable to hold all parameters supplied by the caller of the function.
It is an arbitrary number of arguments in a method or constructor. It contains a list of arguments in a method, function, or constructor.
A simplier way of saying is that, a vararg is a variable token that accepts an arbitrary number of arguments in a method, function, or constructor.
Let's put it this way: When you create a method, a function, or a constructor, you have to declare your method, function, or constructor with an exact number of arguments, for example: public function MyMethod($a, $b, $c). Notice that you have three arguments: $a, $b, $c.
Now instead of having to declare an exact number of arguments (3 in the above case), you can use a variable token to declare in your method, function, or constructor to accept an arbitrary unknown number of arguments in your method, function, or constructor. For example: public function MyMethod(...$vararg).
Notice an ellipsis (three dots, ...) in front of the variable $vararg. This is called a vararg.
Consider this function which has a list of arguments, including variadic and non-variadic arguments.
<?php
/**
* Notice the token ... before the variable argument!
* It signifies that the argument length is unknown at design time!
* The actual argument list will be known at run-time when caller of
* this function passes the exact number of arguments!
*
* Also, noted that you can mix both variadic and non-variadic arguments in any function,
* seperating them with commas!
*/
public function variadic_func($nonVariadic, ...$variadic)
{
echo json_encode($variadic);
}
// you can call the function like this at run-time:
variadic_func(1, 2, 3, 4); // prints [2, 3, 4] <--- notice also that it is an array!
// as you can see, the actual number of arguments will
// be varied (hence variadic arguments) depending on the caller
?>
You can include type names as well (Bar in the below case) and it can be added in front of the ellipsis (three dots, ...):
<?php
class Foo
{
// code logic
public function myfoo(Bar ...$bar)
{
// code logic
}
}
// you can call the function like this at run-time:
$foo = new Foo();
$foo->myfoo(1, 2, 3, 4); // prints [2, 3, 4] <--- notice also that it is an array!
?>
You can use the & reference operator as well and it can be added before the ellipsis (three dots, ...), but after the type name (if any). Consider this example:
<?php
class Bar
{
// code logic
// now declare a vararg that points to the actual arguments using a reference operator denoted by &
// the token & is a reference operator that points to the actual address location of
// the actual arguments in the list
public function mybar(Foo &...$foo)
{
// code logic
}
}
// you can call the function like this at run-time:
$bar = new Bar();
$bar->mybar(1, 2, 3, 4); // prints [2, 3, 4] <--- notice also that it is an array!
?>
There you have it!!!
Arrays and objects are different things in PHP, although they share some functionality. You can use an array as a dictionary-like data structure, meaning, you can use arrays by referring to their key indexes, for example, $profile = [], $profile['firstName'] = 'John', $profile['lastName'] = 'Doe', $profile['address'] = '123 Main St', etc.
In an object, you'll have to specify the whole object that contains its indexes and then specify the actual index objects, for example, assuming profile is that whole object, then you can assign the actual values to the object like this: $firstName = $profile->firstName= 'John', $lastName = $profile->lastName = 'Doe', $address = $profile->address = '123 Main St', etc.
As you can see, both are objects: array object and regular object. The only difference is the syntax. Arrays use the bracket characters [], while objects use the "arrow" operator (->). If you try to use array brackets to access the values on on object, PHP will issue a fatal error:
Fatal error: Cannot use object of type stdClass as array ...
Most of this is common knowledge to working PHP programmers. What's less commonly known is PHP's neat trick to allow end-user-programmers to define what should happen when a programmer tries to access object properties with array syntax. Put another way, you can give your objects the ability to work with array brackets ($myObject[]).
As you can see, $myObject[] is an object using array syntax to work with its object properties.
Because of a common confusion between array access and regular object access, PHP came up a better solution to solve this confusion between array object and regular object by providing an interface called ArrayAccess.
Yes, the goal of this tutorial is not to explain what an array and object are, but rather, to explain what an array access is, and how to go about in using it, using a PHP's especial trick to allow programmers to access object properties using array syntax.
An ArrayAccess is a PHP interface that allow programmers to access object properties using array syntax. That's all that is -- allowing object properties to be accessed using array syntax.
There are situations where it is very convenient to access object properties using array syntax and PHP's ArrayAccess interface aims to do just that.
To start, you need to create a class and implement an interface called ArrayAccess along with its four methods: offsetExists(), offsetGet(), offsetSet(), offsetUnset(). For example:
<?php
/**
* Here is a barebone skeleton without the four methods
*/
class MyClass implements ArrayAccess
{
// code body ....
}
// Now let's try to assign a value to the property and then access it using both
// array and object syntaxes:
$object = new MyClass();
// assigning property 'foo' using array syntax
$object['foo'] = 'bar';
// accessing property 'foo' using array syntax
echo $object['foo']; // output nothing!
// accessing property 'foo' using object syntax
echo $object->foo; // output nothing!
// assigning property 'foo' using object syntax
$object->foo = 'bar';
// accessing property 'foo' using array syntax
echo $object['foo']; // output nothing!
// accessing property 'foo' using object syntax
echo $object->foo; // output nothing!
?>
As you can see, it uses array syntax to work with the object. The beauty about it is that, you can use the regular object syntax as well and it will work just fine. So you have two choices now to work with the object and using either one or both is just a matter of choice.
However, without the four methods, the above example won't do anything. So we need to implement the interface's four methods as well in order for it to do anything, and it looks like the following.
<?php
/**
* How do you implement the four interface methods?
* The documentation on PHP's website about implementing ArrayAccess's four methods is very vague and confusing.
*
* Anyhow, let's implement the four methods and see if we can learn anything from it.
*/
class MyClass implements ArrayAccess
{
// now let's implement the four methods by just echoing out its method name
public function offsetExists($offset)
{
// now whenever you test a property of this MyClass, whether it exists or not,
// behind the scene PHP calls this method called offsetExists($offset),
// passing a property name contains in $offset to this method!
// that's all PHP does behind the scene and nothing else!
// the rest is up to you to implement any way you desire!
// the below statement just echoing out its method name: offsetExists
echo __METHOD__, "\n";
}
public function offsetGet($offset)
{
// now whenever you access a property of this MyClass, say:
// $object = new MyClass();
// $myvarproperty = $object['foo'];
// behind the scene PHP calls this method called offsetGet($offset),
// passing a property name 'foo' (contains in $offset) to this method!
// that's all PHP does behind the scene and nothing else!
// the rest is up to you to implement any way you desire!
// the below statement just echoing out its method name: offsetGet
echo __METHOD__, "\n";
}
public function offsetSet($offset, $value)
{
// now whenever you assign a property of this MyClass, say:
// $object = new MyClass();
// $object['foo'] = 'bar',
// behind the scene PHP calls this method called offsetSet($offset, $value), passing
// a property name 'foo' (in $offset) and its value 'bar' (in $value) to this method!
// that's all PHP does behind the scene and nothing else!
// the rest is up to you to implement any way you desire!
// the below statement just echoing out its method name: offsetSet
echo __METHOD__, "\n";
}
public function offsetUnset($offset)
{
// now whenever you un-assign or unset a property of this MyClass, say:
// $object = new MyClass();
// $object['foo'] = '',
// behind the scene PHP calls this method called offsetSet($offset), passing
// a property name 'foo' (in $offset) to this method!
// that's all PHP does behind the scene and nothing else!
// the rest is up to you to implement any way you desire!
// the below statement just echoing out its method name: offsetUnset
echo __METHOD__, "\n";
}
}
?>
As you can see from the above illustration, PHP does nothing as to what should be implemented inside the four methods. This is by design as to allow programmers the flexibility to implement their own unique ways.
Let's see one way of implememtation that looks like the following.
<?php
/**
* As a rule of thumb, you shouldn't have to do much in these four methods and
* the example shown in these four methods should be suffice, only minor modifications needed!
*
* You should implement other code logic to augment these four methods as well.
*/
class MyClass implements ArrayAccess
{
// declaring a protected property
protected $data = array();
public function offsetExists($offset)
{
// now whenever you test a property of this MyClass, whether it exists or not,
// behind the scene PHP calls this method called offsetExists($offset),
// passing a property name contains in $offset to this method!
// that's all PHP does behind the scene and nothing else!
// the rest is up to you to implement any way you desire!
// let's return if our protected property $data exists or not
return array_key_exists($offset, $this->data);
}
public function offsetGet($offset)
{
// now whenever you access a property of this MyClass, say:
// $object = new MyClass();
// $myvarproperty = $object['foo'];
// behind the scene PHP calls this method called offsetGet($offset),
// passing a property name 'foo' (contains in $offset) to this method!
// that's all PHP does behind the scene and nothing else!
// the rest is up to you to implement any way you desire!
// let's just return our protected property $data
return $this->data[$offset];
}
public function offsetSet($offset, $value)
{
// now whenever you assign a property of this MyClass, say:
// $object = new MyClass();
// $object['foo'] = 'bar',
// behind the scene PHP calls this method called offsetSet($offset, $value), passing
// a property name 'foo' (in $offset) and its value 'bar' (in $value) to this method!
// that's all PHP does behind the scene and nothing else!
// the rest is up to you to implement any way you desire!
// let's set our protected property $data passed in by PHP in $value
$this->data[$offset] = $value;
}
public function offsetUnset($offset)
{
// now whenever you un-assign or unset a property of this MyClass, say:
// $object = new MyClass();
// $object['foo'] = '',
// behind the scene PHP calls this method called offsetSet($offset), passing
// a property name 'foo' (in $offset) containing a null value to this method!
// that's all PHP does behind the scene and nothing else!
// the rest is up to you to implement any way you desire!
// let's unset our protected property $data using index key passed in by PHP in $offset
unset($this->data[$offset]);
}
}
// Now let's try to assign a value to the property and then access it using both
// array and object syntaxes:
$object = new MyClass();
// assigning property 'foo' using array syntax
$object['foo'] = 'bar';
// accessing property 'foo' using array syntax
echo $object['foo']; // bar
// accessing property 'foo' using object syntax
echo $object->foo; // bar
// assigning property 'foo' using object syntax
$object->foo = 'bar';
// accessing property 'foo' using array syntax
echo $object['foo']; // bar
// accessing property 'foo' using object syntax
echo $object->foo; // bar
?>
Here is another one that can accomplish the job as well.
<?php
/**
* As a rule of thumb, you shouldn't have to do much in these four methods and
* the example shown in these four methods should be suffice, only minor modifications needed!
*
* You should implement other code logic to augment these four methods as well.
*/
class MyOtherClass implements ArrayAccess
{
// declaring a protected property
protected $data = array();
// declaring a constructor
public function __construct($data[])
{
// $this refers to the current object: $obj = new MyOtherClass(['zero', 'one']);
$this->data = $data;
}
public function offsetExists($index)
{
// now whenever you test a property $data of this MyClass, whether it exists or not,
// behind the scene PHP calls this method called offsetExists($index),
// passing a property name contains in $index to this method!
// that's all PHP does behind the scene and nothing else!
// the rest is up to you to implement any way you desire!
// let's return if our protected property $data exists/sets or not
return isset($this->data[$index]);
}
public function offsetGet($index)
{
// now whenever you access a property of this MyClass, say:
// $object = new MyClass(['zero', 'one']);
// $mypropertyone = $object['one'];
// behind the scene PHP calls this method called offsetGet($index),
// passing a property name 'one' (contains in $index) to this method!
// that's all PHP does behind the scene and nothing else!
// the rest is up to you to implement any way you desire!
// let's just return our protected property $data
if ($this->offsetExists($index]))
{
return $this->data[$index];
}
else
{
return false;
}
}
public function offsetSet($index, $value)
{
// now whenever you assign a property of this MyClass, say:
// $object = new MyClass(['zero', 'one']);
// $object['zero'] = 'testing',
// behind the scene PHP calls this method called offsetSet($index, $value), passing
// a property name 'zero' (in $index) and its value 'testing' (in $value) to this method!
// that's all PHP does behind the scene and nothing else!
// the rest is up to you to implement any way you desire!
// let's set our protected property $data passed in by PHP in $value
if ($index)
{
$this->data[$index] = $value;
}
else
{
$this->data[] = $value;
}
return true;
}
public function offsetUnset($index)
{
// now whenever you un-assign or unset a property of this MyClass, say:
// $object = new MyClass(['zero', 'one']);
// $object['one'] = '',
// behind the scene PHP calls this method called offsetSet($index), passing
// a property name 'one' (in $index) containing a null value to this method!
// that's all PHP does behind the scene and nothing else!
// the rest is up to you to implement any way you desire!
// let's unset our protected property $data using index key passed in by PHP in $index
unset($this->data[$index]);
return true;
}
}
// Now let's try to assign a value to the property and then access it using both
// array and object syntaxes:
$object = new MyClass(['zero', 'one']);
// assigning properties using array syntax
$object[] = 'two';
$object[] = 'three';
// accessing property 'zero' using array syntax
echo $object['zero']; // two
// accessing property 'one' using object syntax
echo $object->one; // three
// assigning properties using object syntax
$object->property1 = 'property value 1';
$object->property2 = 'property value 2';
// accessing property 'property1' using array syntax
echo $object['property1']; // property value 1
// accessing property 'property2' using object syntax
echo $object->property2; // property value 2
?>
There you have it!!!
call_user_func() is a PHP callback function. A callback is a function that is to be executed after another function has finished executing -- hence the name 'call back'. A callback function is a function that is passed as an argument to another function, to be "called back" at a later time after another function has finished executing. Let's see how a PHP callback function call_user_func() works. For example:
File: simple.php.
<php
class Simple
{
// creating a simple callback function
public function simpleCallBack()
{
echo 'Hello, World!';
}
// creating a simple method to use call_user_func() function
public function simpleMethod()
{
/**
* normally you call a function/method using a class object and a function name.
* for example, $obj->simpleCallBack()
* or in the case of a static method:
* Simple::simpleCallBack()
*
* now with a callback, you are calling it using call_user_func() and
* passing a callback function name as a string to call_user_func() function.
* Then call_user_func() function calls the actual callback function and
* passes any arguments to it as well (if any).
* in the simple case below there isn't any argument to be passed to.
*/
$callback = call_user_func('simpleCallBack');
return $callback;
}
}
?>
Now we can use the above function like this:
<php
class UseSimple
{
// creating an instance of class Simple:
obj = new Simple();
// this statement will output: Hello, World!
obj->simpleMethod();
}
?>
Let's see some more examples:
File: simple.php.
<php
class Simple
{
// creating a simple "static" callback function
public static function simpleCallBack()
{
echo 'Hello, World!';
}
// creating a simple method to use call_user_func() function
public function simpleMethod()
{
/**
* this time, we're dealing with a "static" callback function and we need to
* pass the class' name as well as the callback function name
*/
$callback = call_user_func(['Simple', 'simpleCallBack']);
// or you could do like this as well and you get the same result:
// $callback = call_user_func(['Simple::simpleCallBack']);
return $callback;
}
}
?>
Now we can use the above function like this:
<php
class UseSimple
{
// creating an instance of class Simple:
obj = new Simple();
// this statement will output: Hello, World!
obj->simpleMethod();
}
?>
Let's see some more examples:
File: simple.php.
<php
class Simple
{
// creating a simple "static" callback function
public static function simpleCallBack()
{
echo 'Hello, World!';
}
// creating a simple method to use call_user_func() function
public function simpleMethod()
{
/**
* this time, we will use an "Object" method call instead of
* the "static" method call! $this refers to the current class "Simple" object!
*/
$callback = call_user_func([$this, 'simpleCallBack']);
/**
* or you could do this as well: creating an instance of class Simple.
* $obj = new Simple();
* however, using $this as in the above case is more sexy!
* $callback = call_user_func([$obj, 'simpleCallBack']);
*/
return $callback;
}
}
?>
Now we can use the above function like this:
<php
class UseSimple
{
// creating an instance of class Simple:
obj = new Simple();
// this statement will output: Hello, World!
obj->simpleMethod();
}
?>
Let's see some more examples:
File: foo.php.
<php
class Foo
{
// creating a relative static class callback function
public static function callBack()
{
echo 'Foo!';
}
// creating a method to use call_user_func() function
public function Method()
{
/**
* this time, we're passing a child class' name 'Bar' as well as the
* parent's callback function name 'callBack'
* this will output: Foo!
*/
$callback = call_user_func(['Bar', 'parent::callBack']);
return $callback;
}
}
?>
Now consider this as well:
File: bar.php.
<php
class Bar extends Foo
{
// overriding a relative static parent class callback function "callBack"
public static function callBack()
{
echo 'Bar!';
}
// creating a method to use call_user_func() function
public function Method()
{
/**
* this time, we're passing this child class' name 'Bar' as well as the
* parent's callback function name 'callBack'
* this will output: Foo!
*
* now what if we're passing this child class' name 'Bar' as well as this
* child's callback function name 'callBack'. what is the output?
* the 'callBack' didn't specify which callback to use and it defaults to
* the current object which is the child Bar. so this will output: Bar!
*/
$callback = call_user_func(['Bar', 'parent::callBack']);
return $callback;
}
}
?>
Now we can use the above function like this:
<php
class relativeStatic
{
// creating an instance of class Bar:
obj = new Bar();
// this statement will output: Foo!
obj->Method();
}
?>
Let's see some more examples:
File: foo.php.
<php
class Foo
{
// declaring a variable to hold the name of a callback function
public $callback = 'callBack';
// creating a method passing a callback function name as an argument
public function myMethod($this, $callback)
{
/**
* the call to call_user_func() will execute the callback function named
* "callBack".
*/
$callback = call_user_func([$this, $callback]);
return $callback;
}
public function callBack()
{
/**
* return the string value: "Hello, World!" to myMethod() which
* calls this function
*/
return 'Hello, World!';
}
}
?>
Now we can use the above function like this:
<php
class Bar
{
// creating an instance of class Foo:
obj = new Foo();
// this statement will output: Hello, World!
obj->myMethod();
}
?>
Let's see some more examples:
<php
class Download
{
/**
* create a function passing a callback function as an argument:
* $callback = ['CallBack', 'downloadComplete']
*/
public function downloadFile($file, $callback = NULL)
{
// declaring an array variable
$site = array();
foreach ($file as $key => $value)
{
// simulated downlaod action in each download!
sleep(2);
$data = 'Downloaded content from each file.';
if (is_callable($callback))
{
call_user_func($callback, $value, $data));
}
}
$site = [
'file' => $value,
'data' => $data,
]
return $site;
} // end downloadFile()
} // end class Download
?>
Let's define a class to use the callback. For example:
<php
class CallBack
{
// declaring an array variable
$site = array();
// create a static callback function called downloadComplete()
public static function downloadComplete($file, $data)
{
// declaring an array variable
echo sprint("Finished downloading from %s%", $file);
} // end downloadFile()
} // end class Download
?>
Now let's create another class to use the callBack class. For example:
<php
class UseCallBack
{
// a list of files to download
$site = [
'http://site1.com',
'http://site2.com',
]
// start the download process
downloadFile($file, ['CallBack' 'downloadComplete']);
} // end class Download
?>
First of all before we get into the $this verses self verses parent descriptions, let's investigate an important key player that makes self and parent function the way they do.
That key player is called the Scope Resolution Operator, an operator similar to the PHP's "->" arrow accessor, or "." (a dot) accessor in other languages. For example:
// in PHP: pay close attention to the "->"
$value = $obj->getValue();
// and in other languaes: pay close attention to the "."
value = obj.getValue();
Now the Scope Resolution Operator (or in simpler terms, the double colon) looks like this:
// in PHP: pay close attention to the "::"
$value = MyClass::getValue();
// and in other languaes: it looks the same as PHP's "::"
value = MyClass::getValue();
The Scope Resolution Operator "::" (also called Paamayim Nekudotayim) or in simpler terms, the double colon, is a token that allows access to static, constant, and overridden properties or methods of a class.
In other words, it is a static class operator used to refer to static constant, (static) properties, and (static) methods of a class.
When referencing these items from inside the class definition, use the "self" keyword (more on self later). When referencing these items from outside the class definition, use the name of the class. For example:
// in PHP: using the name of the class: MyClass
$value = MyClass::getValue();
// in other languaes: the same as PHP's: using the name of the class: MyClass
value = MyClass::getValue();
The "::" accesses a (static) constant, a "static" property, and a "static" method similar to using an arrow "->" as an object accessor to access a non-static property and a non-static method.
What is the difference between $this and self?
$this and self are similar in meaning and both achieve the same result. But they're used in different ways.
Inside a class definition, $this refers to the current object, while self refers to the current class. Both are similar in meaning and both achieve the same result.
It is necessary to refer to a class element using self, and refer to an object element using $this.So there is the difference, if any, self refers to a class element while $this refers to an object element. See more examples along with explanations throughout the following two sections.
"self" is a special object directive variable that refers (or points) to the current class itself--"itself" -- get it? The current class itself!
On the other hand, "parent" is also a special object directive variable that refers (or points) to the current class' parent class--the class that the current class inherited from!
Let's see some examples to help you understand better. For example:
<php
class Foo
{
/**
* Description:
*
* "::" is a token that allows access to static, constant, and overridden properties
* or methods of a class.
*
* according to the description there are three items that "::" is being used.
* but the description left out two more cases, and that is: accessing self and parent.
*
* let's see the first three items first and then we'll see the latter two last.
*/
/**
* according to the description it states: "::" allows access to
* static constant of a class.
* let's see what that means by declaring a constant variable to be used with "::".
* notice that all constants are static--no keyword "static" needed!
*/
const ORIGINAL_ENGINE_SIZE = '4.0-liter';
/**
* according to the description it states: "::" allows access to
* static overriden properties of a class.
* okay, let's see what that means by declaring a static property variable to be
* used with "::".
*/
public static $color = 'blue';
/**
*
* we'll declare a non-static overriden property variable as well just to be different!
*/
public $model = 'F150';
/**
* according to the description it states: "::" allows access to
* static overriden methods of a class.
* okay, let's see what that means by creating a static function called staticMethod())
* to be used with "::".
*/
public static function staticMethod()
{
/**
* make note of the use of the "self" and the "::"
* what happens if you replace "self::$color" with "self::$model" ?
* it will give you an error saying cannot access a non-static variable with self
* so if you want to access the non-static properties use $this->model
*/
// output: "The color is blue"
echo sprint("The color is %s%", self::$color);
/**
* likewise, to refer to this static constant. all constants are static!
* output: "The original engine is 4.0-liter"
*/
echo sprint("The original engine is %s%", self::ORIGINAL_ENGINE_SIZE);
/**
* make note of the use of the "self" and the "::" to refer to
* a "non-static" Method()
* this is illegal! you have to use "$this"
*/
self::Method(); // same as Foo::Method() <-- use $this instead
/**
* to refer to the non-static Method() do this:
*/
$this->Method();
/**
* likewise, to refer to this staticMethod() we do a re-cursive call--call itself!
*/
self::staticMethod(); // this is perfectly legal!
/**
* "self" can be used without the "::" as well. consider this:
* $obj is an instance of class Foo
*/
$obj = new Foo();
// or we could do this as well and it works the same way:
$obj = new self;
/**
* in the "if" statement below, $obj is referring to either form above.
* so you can use either form above and it will work just fine!
*
if ($obj instanceof self) /** "self" referring to Foo **/
{
// yes, $obj is an instance of class Foo
sprint("obj is an instance of %s%", $obj instanceof self);
}
}
/**
* okay, create a non-static function called Method() as well just to be different!
*/
public function Method()
{
/**
* output: "The model is F150"
* $this refers to the current object element: $model
*
* wait a minute: is $model the current object element?
* is $model an object or a class property?
*
* if you read my other tutorial called class verses object, you'll know
* that class and object both have the same meaning and achieve the same result,
* but each being used differently.
*
* properties like $model are stored in a permanent memory address location while
* objects like $this (or $this->model) are stored in a temporary location
* called RAM.
*/
echo sprint("The model is %s%", $this->model);
/**
* make note of the use: "self" and "::" to refer to the constant value.
*
* output: "The original engine is 4.0-liter"
*/
echo sprint("The original engine is %s%", self::ORIGINAL_ENGINE_SIZE);
/**
* make note of the use of the "self" and the "::" to refer to
* a "static" staticMethod()
*/
self::staticMethod(); // same as Foo::staticMethod()
}
} // end class Foo
?>
The examples shown thus far were from inside the class itself -- inside class Foo.
Now let's see some examples from outside the class -- particularly outside class Foo. For example:
<php
class UseFoo
{
// declaring a variable.
$foo = 'Foo';
/**
* make note of the use of variable: "$foo" to refer to the class name and
* the "::" to refer to the constant value.
*
* output: "The original engine is 4.0-liter"
*/
echo sprint("The original engine is %s%", $foo::ORIGINAL_ENGINE_SIZE);
/**
* likewise, the use of the class name: "Foo" to refer to the class name and
* the "::" to refer to the constant value.
*
* output: "The original engine is 4.0-liter"
*/
echo sprint("The original engine is %s%", Foo::ORIGINAL_ENGINE_SIZE);
/**
* likewise, the use of the class name: "Foo" to refer to the class name and
* the "::" to refer to the static variable property $color.
*
* output: "The color is blue"
*/
echo sprint("The color is %s%", Foo::$color);
/**
* to refer to staticMethod() do this:
*/
Foo::staticMethod();
/**
* to refer to non-static Method() do this: you already knew that!
*/
$obj = new Foo();
$obj->Method();
/**
* "self" can be used without the "::" as well. consider this:
* is $obj an instance of class UseFoo?
*/
if ($obj instanceof self)
{
// no, $obj is not an instance of class UseFoo, it's an instance of Foo!
sprint("no, obj is not an instance of %s%, it's an instance of Foo!",
$obj = $obj instanceof self? instanceof self : instanceof self);
}
// now $obj is an instance of UseFoo because of the object assingment above
// so the output: obj is an instance of UseFoo
sprint("obj is an instance of %s%", $obj instanceof self);
}
?>
Yes, the latter part of the code example above is a little too complex than it needs to be, but it illustrates the many ways self usage can be used.
Now let's see some examples about parent and more $this examples as well. For example:
<php
class Foo
{
// declaring (parent) array variable to hold class objects--instances of classes.
public $instance = [];
// declaring (parent) class properties
public $make;
public $model;
public $color;
// declaring parent constructor
public function __construct($make, $model, $color)
{
// $this refers to the current object element or current class property
$this->make = $make;
$this->model = $model;
$this->color = $color;
/**
* another example about using $this
*
* if you look at the top of this class Foo, you'll notice that there is an array
* property variable called $instance to hold instances of classes.
* we'll use that property variable to demonstrate another way $this can be used.
* $this on the left side refers to the current object property while $this on
* the right side refers to the current class object or a copy of the
* class Foo object.
*/
$this->instance = $this;
/**
* what that one line of code above does is that it assigns an instance of
* class Foo object to its property variable called $instance.
* it's a copy of itself stored in its own property variable called $instance.
* this is perfectly legal!
*
* now child classes can just refer to this property variable called $instance if
* they want to use class Foo's instance object.
* you'll see sophisticated programmers make use $this to assign it to
* some variables a lot!
*/
}
protected function myFunc()
{
/**
* notice the recursive call to myFunc()--a call to itself from inside itself!
* notice the use of the class name "Foo" instead of "self"
* it is perfectly legal!
* we could as well use "self" in place of "Foo" and it is perfectly legal!
*/
echo sprint("This is a recursive call: %s%", Foo::myFunc());
}
}
?>
Now let's see the effect of using "parent::". For example:
<php
class Bar extends Foo
{
// declaring child class properties
public $rebate;
public $tax;
// declaring child class constructor with two additional argument parameters
public function __construct($make, $model, $color, $rebate, $tax)
{
/**
* right here where we use the keyword "parent" to refer to parent class "Foo"
* so it has the same effect as the non-inherited: Foo::__construct()
*
* notice that you still have to pass the same number of argument parameters: 3
*/
parent::__construct($make, $model, $color); /** calls Foo's __construct() **/
// $this refers to the current object element or current class property
$this->rebate = $rebate;
$this->tax = $tax;
}
// override parent's function definition
public function myFunc()
{
/**
* now call the parent function and if you look in the parent function,
* it echo out: The color is blue
* and that's exactly what this call to the parent function does.
* it outputs: The color is blue
* this has the same effect as the non-inherited: Foo::myFunc()
*/
parent::myFunc(); /** calls Foo's myFunc() **/
/**
* now here is a trick!
* look at the echo statement below and see if you understand the consequence
*
* what is the output? I'll leave it to you to make sense of it!
*/
echo sprint("The answer is %s%", Bar::myFunc());
}
}
?>
There you have it! $this verses self verses parent are three amigos that get used on a regular basis by everyday programmers. These three amigos are very powerful when used the right way. Have a go at them!
Both static and final are special visibility clauses (similar to public, protected, and private). Self is a class object. For more explanation and examples, see $this verses self verses parent tutorial.
Declaring class properties or methods as static make them accessible without needing an instantiation of the class. A property declared as static cannot be accessed with an instantiated class object using "->".
However, a static method can access that property declared as static (see inside aStaticMethod() as an example). To declare methods and properties as static use the keyword static in the front of the method or property, with the method containing the keyword function as well. For example:
<?php
// declaring class properties and methods as static
class Foo
{
// static properties cannot be accessed through the object using the arrow operator ->
// declaring static properties
static $id;
static $name;
static $email;
// static properties may only be initialized using a literal or constant. For example:
static $color = 'white';
static $make = 'Honda';
static $model = 'civic';
// static constant properties are not needed -- redundant! For example: this is illegal!
static const COMMAND_EVENT_FIRE = 'command_fire';
// it is redundant! not needed!
// you can achieve the same thing by removing word 'const' and replace it with the word 'static'
// for example, this is legal!
const COMMAND_EVENT_FIRE = 'command_fire';
// this is legal!
public static function aStaticMethod()
{
// here inside a static method!
// because static methods are callable without an instance of the object created,
// the variable $this is not available inside the method declared as static.
// $this refers to an object or an instance of the current object.
// so the following is illegal!
$this->id;
// so what to do about $id?
// well, you could use 'self' instead.
// the following is legal!
self::$id;
// the following are also legal!
self::$name;
self::$email;
}
}
?>
If no visibility declaration is used (as in the above case for properties), then the properties (or methods) will be treated as if they were declared as public. Now you can access the static method (aStaticMethod()) and properties like this:
<?php
// notice the use of the "::" double colon to refer to a static property or method
// remember that you cannot use "->" as in Foo->aStaticMethod()
// you have to use the "::" double colon to refer to a static property or method
Foo::aStaticMethod();
// or you can use "self"
self::aStaticMethod();
$classname = 'Foo';
$classname::aStaticMethod();
// that was a fancy way of doing this:
Foo::aStaticMethod();
// or this using "self"
self::aStaticMethod();
?>
Static method/function are properties of the class that can be invoked/accessed directly outside the class without needing to instantiate them first. Make note: 'invoking or accessing them directly outside the class without needing to instantiate them first.'
In the example above, you can access class Foo's property aStaticMethod() directly without having to instantiate class Foo first by using the scope resolution operator (::).
In the following example, you can access class Bar's method barStatic() directly using the scope resolution operator (::) because method barStatic() was declared as a static method.
As you can see, you do not need to instantiate class Bar first (nor can you instantiate them first) in order to be able to access method barStatic(). Simply put: you cannot access or invoke static methods via object instantiation using object reference: ->.
To invoke/access static method/function directly outside the class without needing to instantiate it first, you need to use the scope resolution operator (::). For example:
<?php
// this code is outside class Bar definition
Bar::barStatic();
?>
Let's see some more examples:
<?php
// declaring class properties and methods as static
class Foo
{
// declaring static properties with constant values
static $color = 'white';
static $make = 'Honda';
static $model = 'civic';
public static function car()
{
// inside a static method!
// remember that we cannot use "->"
// so we have to use "self" as well as scope resolution operator (::)
return self::$model;
// or if calling from another method outside of class Foo
// return Foo::$model;
}
}
// declaring class Bar properties and methods as static
class Bar extends Foo
{
public static function barStatic()
{
// inside a static method!
// remember that we cannot use "->"
// so we have to use "self" as well as scope resolution operator (::)
return parent::$color; // output: white
// we can as well refer to parent class Foo's static method: return parent::car; // output: civic
// notice that we use 'parent' to refer to parent class Foo's static property 'color'
// and as well as parent class Foo's static method 'car'
// remember that we cannot use "->"
// so we have to use "self" as well as scope resolution operator (::)
// return self::$color; // output: white
// or if calling from another method outside of class Foo
// return Foo::$color;
}
}
?>
Now we can do these:
<?php
print Foo::model() . "\n"; // output: civic
// now via an object
$foo = new Foo();
// now check this out via an object using a double colon
print $foo::$car() . "\n"; // output: civic
print $foo->model() . "\n"; // output: Undefined "Property" model
$className = 'Foo';
print $classname::$model . "\n"; // output: civic
print Bar::$color . "\n"; // output: white
print Bar::$make . "\n"; // output: Honda
print Bar::$model . "\n"; // output: civic
// now via a Bar object
$bar = new Bar();
print $bar->barStatic() . "\n"; // output: white
?>
For more explanation on this subject, please check out the following link:
What is the difference between new self and new static?What is the difference between new self() and new static()?
Both create an instance of a current class. Let's see an example to get a better visualization:
<?php
class Foo
{
// create an instance of class Foo
public static function getSelf()
{
// here, self() is referring to class Foo
return new self();
}
// likewise, create an instance of class Foo
public static function getStatic()
{
// here, likewise, static() is referring to class Foo
return new static();
}
}
?>
So, what is the difference between new self() and new static()?
As you can see, there is absolutely no difference at all! They both return instances of their own class, which is class Foo.
However, consider the following to see the difference between new self() and new static():
<?php
class Bar extends Foo
{
// additional class Bar code!
}
?>
Let's create another class to see the effect between new self() and new static():
<?php
class Stranger
{
/**
* return instances of class Foo
* here, we call Foo's method from outside class Foo using a class name and an "::".
* getSelf() returns its own class name Foo.
* while getStatic() also returns its own class name Foo
* so there is no difference!
*/
echo (Foo::getSelf()); // Foo
echo (Foo::getStatic()); // Foo
/**
* here, likewise, we call Bar's method from outside class Bar using a
* class name and an "::".
* but class Bar doesn't have getSelf(); however, class Bar extends from class Foo,
* and therefore, class Bar gets getSelf() from class Foo through inheritcance.
* so getSelf() returns its own class name, which is Foo.
*
* meanwhile, getStatic() also returns its own "static" class name, which is Bar.
* make note: "own" "static"--more specifically, "static". so there is a difference!
*
* notice the reference to Bar::getStatic() but class Bar doesn't have getStatic().
* however, class Bar gets getStatic() from class Foo through inheritcance.
* so Bar::getStatic() is like class Bar referring to its "own" method getStatic()
* and that's why Bar::getStatic() returns Bar.
* so it is bear repeating: there is a difference!
*/
echo (Bar::getSelf()); // Foo
echo (Bar::getStatic()); // Bar
}
?>
There you have it: the difference between new self() and new static().
Next up is the final visibility tutorial. A final visibility is similar to a static visibility programming.
PHP's final visibility prevents child classes from overriding a method by prefixing the definition with final. If the class itself is being defined as final then it cannot be extended.
So the keyword 'final' means that is it: no more to be had! It can't be extended. It's final!
Let's see some examples.
If a class itself is being defined as "final" then it cannot be extended:
<?php
// here, a class is being defined as "final" and therefore it cannot be extended
final class Foo
{
private function methodName1()
{
// code logic
}
// this "final" keyword declaration is not matter because the class
// "final" keyword declaration supersedes anything else
final public function methodName2()
{
// code logic
}
}
?>
Now consider this:
<?php
// declaring class properties and methods as static
class BaseFoo
{
// declaring an ordinary function without a "final" keyword
// this means that child classes can extend this BadeFoo class
public function test()
{
// echoing out the ordinary function test()
// so in effect, it calls itself (function test()). it's a recursive call.
// no "final" keyword so no problem here!
echo "BaseFoo::test() called\n";
}
// declaring a function with a "final" keyword
// watch out child classes: you can't extend this parent class!
final public function moreTesting()
{
// echoing out the "final" function moreTesting()
// again, it calls itself (function moreTesting()). it's a recursive call.
// and no problem here, either, as of now!
// later it could be a problem if child classes try to extend from this class!
echo "BaseFoo::moreTesting() called\n";
}
}
?>
Let's see some child classes examples to see if they want to cause some problems:
<?php
// declaring child class definition and extending from parent class BaseFoo
class ChildClass extends BaseFoo
{
// overriding a parent's method called moreTesting() that has a "final" keyword on it
// this will cause a problem!
// you cannot override a parent class with a method declared as "final"
public function moreTesting()
{
// again, it calls itself (function moreTesting()). it's a recursive call.
// This time, it results in a fatal error:
// Cannot override final method BaseFoo::moreTesting()
echo "ChildClass::moreTesting() called\n";
}
}
?>
It would be perfectly fine if child classes just extend from the parent class but don't override the methods with the "final" keyord on them. Just override the ones that don't have "final" keyword on them and it would be just fine.
Let's see some more examples:
<?php
// declaring a base class Foo definition
class Foo
{
// a "private" method declared as "final"
final private function Testing()
{
// again, it calls itself (function moreTesting()). it's a recursive call.
// no error!
echo "Foo::Testing() called\n";
}
}
?>
Let's see some child classes examples to see if they want to cause some problems:
<?php
// declaring child class definition and extending from parent class Foo
class Bar extends Foo
{
// overriding a parent's "private" function that has a "final" keyword on it
// this will cause a problem!
// you cannot override a parent class with a method declared as "final"
// the parent's visibility clause plays no role in this but
// a method declared as "final" is causing a major error problem
private function Testing()
{
// again, it calls itself (function Testing()). it's a recursive call.
// again, it results in a fatal error:
// Cannot override final method Foo::Testing()
echo "Bar::Testing() called\n";
}
}
?>
The right way and the wrong way:
<?php
class Foo
{
// the right way: final public/protected/private function methodName1()
// "final" keyword has to come before any clauses
final private function methodName()
{
// code logic
}
// the wrong way: public/protected/private final function methodName2()
// "final" keyword has to come before any clauses
public final function methodName()
{
// code logic
}
}
?>
So the key point to take away from this is that, a parent's visibility clause plays no role in the error problem, but a method declared as "final" plays a major in causing the code to fail.
Do you ever looking at someone else code and wondering what a block of code is trying to accomplish, or more specifically, what a block of code means?
Here is one of that block of code:
What does the following block of code mean or what does it try to accomplish?
What statement causes the loop while (true) to end?
Or more specifically, when does the loop while (true) end?
<?php
// notice that while (true) can be written as while (1) as well!
while (true)
{
if ('test')
{
// do something
}
else
{
break;
}
}
?>
The answer to the question: 'When does the loop while (true) end?' is dependent on the condition you supplied in your test.
In this case, it ends when the test fails and it goes to the else condition code block and, therefore, the break clause is executed.
When the break clause is executed, it jumps out of the while (true) loop.
Now consider this example:
<?php
public function largePrecisionPowMod($base, $power, $modulus)
{
// start with 1
$result = "1";
// notice that while (true) can be written as while (1) as well!
// loop until the exponent is reduced to zero
while (true)
{
if (bcmod($power, 2) == "1")
{
$result = bcmod(bcmul($result, $base), $modulus);
}
// when the exponent is reduced to zero, we exit the loop
// and return $result
if (($power = bcdiv($power, 2)) == "0")
{
// likewise, when the test condition is true,
// it comes here and executes the 'break' clause, which in turn,
// causes it to jump out of the while (true) loop!
break;
}
$base = bcmod(bcmul($base, $base), $modulus);
} // end while
return ($result);
}
?>
As you can see, there is nothing special about while (true) loops. They are just loops that keeps looping around and around and around indefinitely until you make it jump out of the while (true) loops.
A typical method to make it jumps out of the while (true) loops is to use a break clause.
Here is the code explanation:
<?php
/**
* consider a normal while() loop as you normally write, for example:
*/
while ($i < $n)
{
$i++;
}
/**
* now this is the usual way of doing!
* we have a while loop that contains a condition that
* will allow the loop to exit when $i is greater than $n
*
* but in the while (true) loop it will run indefinitely
* because the condition is always 'true'
*
* so to make the condition false, you have to set that
* conditon somewhere in the body of the while(true) loop
* so that it can exit the loop! very simple!
*
* a typical method to make it jumps out of the while (true) loops is to use a break clause
*/
<?php
/**
* this while (true) loop just keeps running and running and running ...
* until it encounters a 'break' clause!
*
* make note: "until it encounters a 'break' clause"
*/
$test = true;
// notice that while (true) can be written as while (1) as well!
while (true)
{
// now test to see if 'test' condition is still true
if ($test)
{
// the first time 'test' should be true
// the next subsequent iterations are dependent
// on what you set 'test' to be!
// do something that causes 'test' to be false so
// that the next iteration of this 'if' will fail!
// for this example, we'll just set 'test' to false!
$test = false;
// now assuming that 'test' is still true, the while (true)
// will continue to run and run and run ... !
// but in this case, we set 'test' to be false,
// so the next iteration of the while (true) loop will
// still be looping and proceeding to hit the 'if' condition again!
// but this time, the 'if' condition will fail and it goes to
// the 'else' condition, and it encounters a 'break' clause,
// which causes it to jump out of the while (true) loop and ends!
}
else
{
// so if you make the 'if' condition to be 'false',
// it will come here for its next iteration of while (true) loop,
// and therefore it will encounter the 'break' clause, which
// causes it to exit the iteration of while (true) loop!
break;
// notice that you have to put the 'break' clause to
// cause the while (true) loop to exit!
}
here is another example:
this time using only if statement.
so this is not about while (true) loop but it is about 'if'
let's see if you can answer these two questions.
the first 'if' statement (below), will it echo out: 'test is true'?
the second 'if' statement (below), will it echo out: 'test is false'?
so this is not about while (true) loop but it is about 'if'
$test = true;
if ($test)
{
$x = 'test is true';
}
echo $x;
if (false)
{
$x = 'test is false';
}
echo $x;
?>
What was your answer for the first 'if' condition?
How about your answer for the second 'if' condition?
Here is an explanation:
<?php
/**
* first of all, there are two cases we have to clarify:
*
* first, the 'if' condition:
*
* if (condition is true)
* // it should come here even if you don't place curly brackets {}
* after that it comes here as well even if the condition is true or false
*
* do you see the code flow of the 'if' statement?
*
* second, the use of the boolean statement: if (false)
*
* this test implies the earlier boolean condition which was set to true.
*
* in a way, this is similar to the while (true) condition shown earlier!
*
* let's see the answers:
*/
so the first 'if' statement will echo out: 'test is true'
$test = true;
if ($test)
{
$x = 'test is true';
}
notice that you can remove the curly brackets '{}' above as well
and it still functions the same.
echo $x;
now the second 'if' statement will not echo out: 'test is false'
why? do you know why?
see explanation below!
if (false)
{
$x = 'test is false';
}
notice that you can remove the curly brackets '{}' above as well
and it still functions the same.
echo $x;
if (false) implies the earlier boolean condition if it is false.
but the earlier boolean condition was true; and therefore,
the second 'if' statement is false and $x contains null
because the assignment statement to $x was not executed.
very simple!
?>
Here is another example using Python:
<?php
/**
* As you can see in the code example below the 'while True' is always true and
* the loop never exits because there isn't a 'break' clause.
*
* This is by design because the goal of this code is to dispaly an
* image on the screen and because we want to see the image indefinitely,
* and not just a few seconds, we use the 'while True' loop to loop
* indefinitely so that the image being displayed is not all of a sudden
* disappear -- we want to see the image being displayed indefinitely.
*
* This is the reason the 'while True' loop doesn't have a 'break' clause.
*
* The code below is partially listed from an actual functional code.
*/
while True:
index = int(input("Enter a number (0 - 59999): "))
img = images[index]
plt.imshow(img.reshape(28, 28), cmap="Greys")
img.shape += (1,)
# Forward propagation input -> hidden
h_pre = b_i_h + w_i_h @ img.reshape(784, 1)
h = 1 / (1 + np.exp(-h_pre))
# Forward propagation hidden -> output
o_pre = b_h_o + w_h_o @ h
o = 1 / (1 + np.exp(-o_pre))
plt.title(f"Subscribe if its a {o.argmax()} :)")
plt.show()
# The plt.show() shows the image on the screen indefinitley!
# And there is no break clause afterward to exit the loop!
?>
There you have it!
A nice way to code your while (true) loop and as well as a bonus if statement!
For those of you who are interested in building your own web browsers similar to Microsoft's newest web browser called Edge, Google's Chrome, Apple's Safari, Mozilla's Firefox, and Linux's Opera, here are five active web browser rendering engines that you can use to build your own web broswer. Please Google these browser engines to learn more:
WebKit: Safari browser
WebKit is fast, open source web browser engine used by Safari, Mail, App Store, and many other apps on macOS, iOS, and Linux.
WebKit web browser engineBlink: Google Chrome and Chromium-based browsers such as Microsoft Edge browser, Opera browser, Brave browser and Vivaldi browser.
Blink is an open-source browser layout engine developed by Google as part of Chromium (and therefore part of Chrome as well). Specifically, Blink began as a fork of the WebCore library in WebKit, which handles layout, rendering, and DOM, but now stands on its own as a separate rendering engine.
Blink Rendering EngineGecko: Firefox browser
Gecko is a browser engine developed by Mozilla. It is used in the Firefox browser, the Thunderbird email client, and many other projects.
Gecko is designed to support open Internet standards, and is used by different applications to display web pages and, in some cases, an application's user interface itself (by rendering XUL). Gecko offers a rich programming API that makes it suitable for a wide variety of roles in Internet-enabled applications, such as web browsers, content presentation, and client/server.
Gecko is written in C++ and JavaScript, and, since 2016, additionally in Rust. It is free and open-source software subject to the terms of the Mozilla Public License version 2. Mozilla officially supports its use on Android, Linux, macOS, and Windows.
Gecko Home Page Gecko-based browsersGoanna: Pale Moon and Basilisk browsers.
Goanna is an open-source browser engine that is a fork of Mozilla's Gecko. It is used in the Pale Moon browser, the Basilisk browser, and other UXP-based applications. Other uses include a fork of the K-Meleon browser and the Mypal browser for Windows XP.
Goanna as an independent fork of Gecko was first released in January 2016. The project's founder and lead developer, M. C. Straver, had both technical and trademark motives to do this in the context of Pale Moon's increasing divergence from Firefox.
There are two significant aspects of Goanna's divergence: It does not have any of the Rust language components that were added to Gecko during Mozilla's Quantum project, and applications that use Goanna always run in single-process mode, whereas Firefox became a multi-process application. Please Google the term "Goanna browser engine" to learn more.
Pale Moon ProjectFlow: Flow browser
Flow is a web browser with a proprietary rendering engine that claims to "dramatically improve rendering performance." Its JavaScript engine, however, is the SpiderMonkey engine of Firefox. Flow is developed by the Ekioh company, which has made simpler browsers for set-top boxes and other embedded systems.
Flow web browserFor those of you who are interested in creating your own programming language similar to PHP, Javascript, Java, C/C++, C#, Python, Delphi, etc., here is how to go about in finding resources on creating your own compiler. A term "compiler" means a programming engine that runs the program you write in plain text. Say you write your program in PHP or Java in plain text, a PHP or Java compiler will convert your plain text into a PHP or Java readable code.
Please Google the term "Backus-Naur" to learn more.
In computer science, Backus-Naur Form or Backus normal form (BNF) is a metasyntax notation for context-free grammars, often used to describe the syntax of languages used in computing, such as computer programming languages, document formats, instruction sets and communication protocols.
They are applied wherever exact descriptions of languages are needed: for instance, in official language specifications, in manuals, and in textbooks on programming language theory.
Many extensions and variants of the original Backus-Naur notation are used; some are exactly defined, including extended Backus-Naur form (EBNF) and augmented Backus-Naur form (ABNF)
In simple term, the Backus-Naur Form is used to form a flowchart for the lexical program analyzer (or a program parser) for a compiler to read and analyze the text input. For example, if you create a webpage in HTML, you would start by writing an opening <html> and then followed by an opening <head>, followed by an opening <meta>, followed by an opening <title>, followed by the actual title text description, and then followed by the closing </title>, followed by the closing </head>, followed by an opening <body>, followed by the actual content of the 'body', and then followed by the closing </body>, followed by the closing </html>. For example:
/**
* An HTML code for a lexical analyzer to read the grammar
*/
<html>
<head>
<meta .....>
<title>title text description</title>
</head>
<body>
content of the 'body'
</body>
</html>
The lexical analyzer of the compiler will read and analyze the above code using the Backus-Naur Form and then if it is conformed to the Backus-Naur Form, it will hand over to the compiler to translate the code into a machine readable code.
Backus-Naur FormThe easiest way to create your own programming language is to use tools already created by others. Two of the best tools available are called Yacc and JavaCC (or Java Compiler Compiler).
Yacc (Yet Another Compiler-Compiler) is a computer program for the Unix operating system developed by Stephen C. Johnson. It is a Look Ahead Left-to-Right (LALR) parser generator, generating a LALR parser (the part of a compiler that tries to make syntactic sense of the source code) based on a formal grammar, written in a notation similar to Backus-Naur Form (BNF).
The Lex & Yacc Home Page JavaCC: Java Compiler Compiler Lex & Yacc ResourcesYou can check the following link out as well in the topic of creating your own programming languages:
Build your own languages with JavaCCA boolean is a logic that conveys all values are either true or false. That's what a boolean is: a logic that is either true or false.
For example, if you have two logics, one is true, and another is false, the outcome is false. See truth table later for more.
The term boolean was derived from the name of its inventor named George Boole (November 2, 1815 - December 8, 1864).
George Boole, who wrote a book called the Mathematical Analysis of Thought and An Investigation of the Laws of Thought to illustrate his logic, is recognized as the father of modern information technology, ushering the modern technology that basically effecting every facets of our lives today.
From the book, Boole's thinking has become the practical foundation of digital circuit design and the theoretical grounding of the the digital age.
His idea in the book, particlulary the boolean logic, is widely being used in all facets of modern technology, especially in electronics - and more predominantly in modern computing technology.
A contemporary of Charles Babbage, whom he briefly met, George Boole is these days credited as being the "forefather of the information age".
An Englishman by birth, in 1849, he became the first professor of mathematics in Ireland's new Queen's College (now University College) Cork.
Boolean logic is very easy to explain and to understand.
Then you can form other statements, which are true or false, by combining these initial statements together using the fundamental logic operators: And, Or, and Not.
The way that all this works more or less fits in with the way that we used these terms in English.
For example, if X is true then Not(X) is false.
So, if "today is Monday" is true then "Not(today is Monday)" is false.
We often translate the logical expression into English as "today is Not Monday" and this makes it easier to see that it is false if today is indeed Monday.
The rules for combining expressions are usually written down as tables listing all of the possible outcomes. These are called truth tables, and for the three fundamental logic operators, these are:
| Truth Table |
| Input X | Input Y | Output |
| True | True | True |
| True | False | False |
| False | True | False |
| False | False | False |
As you can see from the truth table above, when the input X is true and the input Y is also true, the outcome is also true.
Likewise, when the input X is true and the input Y is false, the outcome is false.
Next, when the input X is false and the input Y is true, the outcome is false.
Likewise, when the input X is false and the input Y is true, the outcome is false.
Lastly, when the input X is false and the input Y is also false, the outcome is false.
/**
* using AND logical operator to test two or more conditions
*/
if ((A > B) AND (B > C))
{
// in order for the condition to be true, both A and B has to be greater than C
....
}
/**
* using OR logical operator to test two or more conditions
*/
if ((A > B) OR (B < C))
{
// in order for the condition to be true, B has to be between A and C
// a simplier way of saying is that, it is true if A > B
// also, it is true as well if B < C
// note that both of the conditions need not to be true
// in order for it to be true!
// only one of the conditions needs to be true
// not necessarily that both of the conditions need not to be true
// in order for it to be true!
}
/**
* using NOT logical operator to test one or more conditions
* notice that logical operator NOT can be used to test
* a single condition as well!
*
* most programming languages use a symbol character '!' to represent 'NOT'
*
* and a lot of programming languages use both the symbol character '!' and
* the word 'NOT' to represent 'NOT'
*
* let's see some examples!
*/
if (!A > B)
{
// in order for the condition to be true, A has to be less than B
}
/**
* using NOT logical operator to test one or more conditions
*/
A = true;
// if not A, meaning if A is not equal to true
if (!A)
{
// in order for the condition to be true, A has to be false
}
/**
* using NOT logical operator to alternate between true and false
*/
alternate = true;
for (i = 0; i < 10; i++)
{
// this assignment basically alternating between true and false
alternate = !alternate;
}
/**
* using boolean logic
*/
// this can also be written as: while (1)
while (true)
{
// this condition basically is an endless while loop!
}
// while not true
// this can also be written as: while (!1)
while (!true)
{
// this condition basically is an endless while loop as well!
}
To be continued!
cURL (or client URL) is a request/response model or protocal that enables to send and receive data to and from the server. In other words, you can use cURL to transfer data to the server and the server will return the data you requested back to you (or more specifically, your client application, hence the word client in cURL). It's a request/response transfer protocol or model!
To transfer data using cURL or to fetch/retrieve data using cURL, you have to write a client script using client-side scripting languages such as PHP, Javascript, ASP, etc.
In this tutorial, we'll use PHP as the client-side scripting language. Let's see some examples with explanations accompanying the illustration. Let's try to retrieve the content of a remote website: any content that appears on the remote website, it's a fair game!
All we need is the url of the remote website and we can get all of the content in the remote website.
In order to download the contents of a remote web site, we need to define the following options:
CURLOPT_RETURNTRANSFER: Enables the assignment of the data that we download from the remote site to a variable, i.e., $result. When we print the value of the variable $result to the screen, we will see the picture/content of a web site being displayed.
The options can be written more compactly using curl_setopt_array(), which is a cURL function that convenes the options into an array.
Okay, let's putting things together. Notice that this example shows a very minimal options that are available. There are lots of options available to set, but for the sake of simplicity, we'll just use the very absolute minimum options. But first, here is a typical skeleton of the cURL script:
<?php
$url = __DIR__ . DIRECTORY_SEPARATOR . "some_remote_file.html";
/**
* initializing curl.
* this is like creating a constructor in other programming
* languages. when this line is executed it will go through a
* series of code initialization.
*/
$curl = curl_init();
/**
* after all of initialization has been done, it opens a
* connection to the url you provided in variable $url.
* the 'w' is to signify to the file protocol that we want
* to send (or 'w'rite to) the remote file (or website).
*/
$fileHandle = fopen($url, "w");
/**
* CURLOPT_URL is the option containing the remote url.
*
* CURLOPT_HEADER is the option containing the client header,
* the header that this browser sends to the remote host.
* setting it to true will send all the header information to the remote host.
* you can send specific header information for debugging purpose by
* specifiying the header property, i.e., HEADER_COOKIE to send cookie.
*
* CURLOPT_RETURNTRANSFER is the option to specify that we
* want cURL to return the requested content back to us.
* setting CURLOPT_RETURNTRANSFER to true does the job.
*
* sometimes, we just want to send the content to the
* remote host and never want to get anything back; for example,
* when you connect to a remote host to use its API services
* such using PayPal credit card payment API, Stripe credit card
* payment API or a stock trading API from some of the brokerage services,
* you don't need to receive the content back through this client
* request initiation.
*
* instead, you just want to connect to the remote host and access their
* API content that is storing in the remote host's server.
*
* in that case, set it to false because you don't want the server to
* send back the whole API content via the internet.
* besides, the remote host would not allow you to do that in the first place.
*
* CURLOPT_FILE option is to allow us to send and receive
* files. in cURL, we can send any content including
* files. using CURLOPT_FILE option allow us to send and
* receive files.
*/
curl_setopt_array($curl, [
CURLOPT_URL => $url,
CURLOPT_HEADER => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FILE => $fileHandle
]
);
/**
* after all of options have been set, it's time to
* send the request to cURL to do its job.
*
* now the call to curl_exec() executes the cURL engine.
*/
$result = curl_exec($curl);
// after that, we can close the cURL engine
curl_close($curl);
/**
* after the close of the cURL engine, it's time to
* get the content sent back by cURL engine.
*
* $result contains the response from the server.
*
* the response from the server contains a long string.
*
* so you would have to format how your content to be
* sent back to the client.
*
* this means that in your remote host script that does all
* of the responses to your client's requests would need to
* format the long string using delimiters, i.e., '|', '&', '#', etc.
*
* how you format your content to be sent back is up to you.
* and once you get the content, you can unravel/unformat your
* content accordingly.
*/
echo $result;
?>
As you can see, it is very easy to use cURL script to transfer data to and from the remote host.
Let's see a real example using cURL script to retrieve the content of a remote website: any content that appears on the remote website, it's a fair game, including a web site of singer Lady Gaga!
In this example, the content data of Lady Gaga's website is assigned to the variable $result. For example:
<?php
$curl = curl_init();
/**
* after all of initialization has been done, we can set
* all of the options needed inline.
*
* these options will connect our client to the remote host
*/
curl_setopt($curl, CURLOPT_URL, "https://www.ladygaga.com");
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_HEADER, false);
$result = curl_exec($curl);
// after that, we can close the cURL engine
curl_close($curl);
/**
* when we echo the value of the variable $result to
* the screen, we will see the picture/content of a web site
* of singer Lady Gaga.
*
* give it a try and see what happens!
*/
echo $result;
?>
cURL script is a very powerful tool for transfering data and receiving data back from the remote host. Please Google the term cURL to learn more using your favorite client-side languages of your choice.
You often see people use color palletes like rgb(50, 150, 255), rgb(0, 125, 005), rgb(160, 050, 205), rgb(255, 050, 109), etc.
What do these mean?
If you answered: they're color schemes, then you're correct!
So the next question is: what is a color scheme or sometimes known as color pallete?
To answer that, let's see some basic principle behind colors.
In screen displays such as computer screen, TV screen, or any electronic display screens, they contain very tiny holes layout in the entire screen pane or screen area. These holes are called pixels.
If you were to take a screen and submerge it under water and lift the screen up water would have dripping down through the pixels or holes and drained down and no water would be able to be held on the screen pane.
So screens are designed to have holes or pixels in them so that lights can shine through them. That is how display screen works by shining lights through pixels or holes.
And that is also how colors are made by shining different light intensity into those pixels.
Each pixel is made up of three separate lights. Each of these is able to change in intensity, from none to full brightness. A signal is sent to every pixel with information about the brightness of each component part: Red, Green, and Blue.
Our eye is sensitive to different wavelengths but creates all the colors we see through three main channels: Long, Medium, and Short wavelengths. The differing quantities of Red, Green, and Blue light emitted activates these receptors to create the sense of color we perceive.
If you look at the pixels of almost any screen display close up, say with a magnifying glass, you'll find that each pixel comprises three smaller areas (called subpixels) that are red, green, and blue - the additive primary colors.
So each pixel on the screen can create the perception of any color desired (as long as that color is within the screen's color gamut) simply by combining different amounts of red, green, and blue light.
All three primaries (or subpixels) lit "full on" makes that pixel white; lighting just the green and red subpixels makes yellow, and so forth.
So every image shown on the screen is really just a set of data for each pixel, which encodes the intended brightness of each of the three subpixels at that location.
So in a simplest term, it is merely shining combinations of lights into the pixels that causes the color to appear distinct from one another; for example, if you shine certain lights on certain pixels it will cause the output of those pixels to show certain color.
So how do we shine those lights into the pixels?
Display screens use hexadecimal numbers to represent lights or colors. Hexa means 16 decimal base number. So hexadecimal number is: 0123456789ABCDEF.
But we use our natural 10 decimal base number: 0123456789.
In other words, colors can be made using hexadecimal numbers: 0123456789ABCDEF and as well as using our natural 10 decimal base numbers: 0123456789.
Knowing that we can multiply 16 X 16 = 256.
Now since the number starts with a zero: 0, the total combinations of possible pixels to shine through is 255, hence rgb(255, 255, 255).
This means that three lights containing one red (r) gamut, one green (g) gamut, and one blue (b) gamut in combinations are shining through the pixels to make the color represents that combination.
So the next question is: how do we know what combination(s) to use to achieve a specific color?
Yes, this is a very good question that no one can tell you exactly what combination(s) to specify. It is merely a case of "trial and error" by first specifying the number, i.e., rgb(115, 209, 080), and have a look at the actual result to see what that combination turns out.
So basically, you just try to put in some numbers combination and take a look at the result of that combination to see if what you're looking for in color.
This is called one combination to generate one particular color: rgb(225, 190, 211) and this is another combination to generate another distinct color (by shining all pixels to lit "full on" makes that pixel white): rgb(255, 255, 255) or this is a white color combination.
So by just turning certain pixels on and off makes the color appears on the display screen.
As stated earlier, color schemes can be made using rgb decimal 10 number format or using hexadecimal number format.
Color schemes have two format: rgb(255, 255, 255) and the hexadecimal representation: #FFFFFF -- that is six digits of hexadecimal representation which is equal to 256 combinations.
In the six digits, you can specify any combination in hexadecimal representation: 0123456789ABCDEF.
For example, to generate a white color (by shining all pixels to lit "full on" makes that pixel white): FFFFFF, turn all pixels off makes it black: 000000, aqua: 00FFFF, red: FF0000, blue: 0000FF, etc.
When using these hexadecimal representation, don't forget to place # in front of it, i.e., a white color: #FFFFFF, black: #000000, aqua: #00FFFF, red: #FF0000, blue: #0000FF, etc.
Let's see how they're being used:
<style>
body
{
background-color: rgb(255, 255, 255); /** background color of the webpage **/
width: 100%;
color: #CCCCFF /** color of the text **/
}
p.one
{
border-style: solid;
border-color: red;
}
p.two
{
border-style: solid;
border-color: green;
}
p.three
{
border-style: dotted;
border-color: blue;
}
/**
* as you can see, the hexadecimal format needs to use "#" in front of
* the hexadecimal numbers.
*
* notice that you can use actual words to specify actual colors as well.
*/
</style>
So the key to remember when specifying the combination is that to use a number between 0 and 255 in the case of RGB in 10-base decimal numbers.
And between 0 to 9 and as well as between A to F in the case of hexadecimal numbers.
So there you have it: a very brief introduction to colors.
Example code to send verification to the phone via text message or voice message using php and javascript.
Sending verification codes to a phone number requires using a third-party service with an SMS or voice API (e.g., Twilio Verify API, Vonage Verify API, or Telesign VerifyClient), as PHP and JavaScript do not have built-in functionality to send text or voice messages directly.
Below is an example using the Twilio Verify API with a combination of HTML/JavaScript (frontend) and PHP (backend).
Sign up for a service like Twilio to get access to their SMS service API.
You'll need your Account SID, Auth Token, and a Verify Service SID, available in the Twilio Console.
Once you've signup, you'll have all the credential information needed for this application.
Install the PHP Helper Library using Composer: composer require twilio/sdk.
Check out instruction at their website on how to install the API.
Those are the three requirements needed to accomplish the job.
Once you have those three steps taken care of, you can begin to write some code.
Here is how to write the code:
This simple form collects the user's phone number and then a verification code, sending requests to the backend PHP scripts using JavaScript.
File: index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Phone Verification</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script>
$(document).ready(function()
{
// Handle sending the verification code
$("#send-code-form").submit(function(event)
{
event.preventDefault();
var phoneNumber = $('#phone_number').val();
$.post("send_verification.php", { phone_number: phoneNumber }, function(data)
{
if (data.success)
{
$('#enter-number-section').fadeOut();
$('#verify-code-section').fadeIn();
alert("Verification code sent!");
}
else
{
alert("Error: " + data.error);
}
}, "json"); // end $.post() block
}); // end $("#send-code-form").submit() block
// Handle verifying the code
$("#verify-code-form").submit(function(event)
{
event.preventDefault();
var phoneNumber = $('#phone_number').val(); // Re-use the number from the first input
var code = $('#verification_code').val();
$.post("verify_code.php", { phone_number: phoneNumber, code: code }, function(data)
{
if (data.success)
{
alert("Phone number verified successfully!");
// Redirect or log in the user
}
else
{
alert("Verification failed: " + data.error);
}
}, "json"); // end $.post() block
}); // end $("#verify-code-form").submit() block
}); // end $(document).ready(function()
</script>
</head>
<body>
<div id="enter-number-section">
<p>Enter your phone number to receive a verification code:</p>
<form id="send-code-form">
<input type="text" name="phone_number" id="phone_number" placeholder="e.g., +15017122661" required />
<button type="submit">Send Code</button>
</form>
</div>
<div id="verify-code-section" style="display: none;">
<p>Enter the 6-digit code sent to your phone:</p>
<form id="verify-code-form">
<input type="text" name="verification_code" id="verification_code" maxlength="6" required />
<button type="submit">Verify Code</button>
</form>
</div>
</body>
</html>
This script uses the Twilio PHP SDK to initiate the verification process (via SMS or voice, configurable in Twilio settings).
File: send_verification.php
<?php
// send_verification.php
require __DIR__ . '/vendor/autoload.php'; // Path to Composer autoload.php
use Twilio\Rest\Client;
// Your Twilio credentials - use environment variables in a production environment for security
$accountSid = getenv('TWILIO_ACCOUNT_SID') ?: 'YOUR_ACCOUNT_SID';
$authToken = getenv('TWILIO_AUTH_TOKEN') ?: 'YOUR_AUTH_TOKEN';
$serviceId = getenv('TWILIO_VERIFY_SERVICE_SID') ?: 'YOUR_VERIFY_SERVICE_SID';
$client = new Client($accountSid, $authToken);
header('Content-Type: application/json');
if ($_SERVER['REQUEST_METHOD'] == 'POST' && !empty($_POST['phone_number']))
{
$phoneNumber = filter_var($_POST['phone_number'], FILTER_SANITIZE_STRING);
try
{
$verification = $client->verify->v2->services($serviceId)
->verifications
->create($phoneNumber, "sms"); // Can specify "call" here for voice
echo json_encode(['success' => true, 'status' => $verification->status]);
}
catch (Exception $e)
{
echo json_encode(['success' => false, 'error' => $e->getMessage()]);
}
}
else
{
echo json_encode(['success' => false, 'error' => 'Invalid request']);
}
?>
This script checks the code submitted by the user against the one managed by the Twilio service.
File: verify_code.php
<?php
// verify_code.php
require __DIR__ . '/vendor/autoload.php'; // Path to Composer autoload.php
use Twilio\Rest\Client;
// Your Twilio credentials
$accountSid = getenv('TWILIO_ACCOUNT_SID') ?: 'YOUR_ACCOUNT_SID';
$authToken = getenv('TWILIO_AUTH_TOKEN') ?: 'YOUR_AUTH_TOKEN';
$serviceId = getenv('TWILIO_VERIFY_SERVICE_SID') ?: 'YOUR_VERIFY_SERVICE_SID';
$client = new Client($accountSid, $authToken);
header('Content-Type: application/json');
if ($_SERVER['REQUEST_METHOD'] == 'POST' && !empty($_POST['phone_number']) && !empty($_POST['code']))
{
$phoneNumber = filter_var($_POST['phone_number'], FILTER_SANITIZE_STRING);
$code = filter_var($_POST['code'], FILTER_SANITIZE_STRING);
try
{
$verificationCheck = $client->verify->v2->services($serviceId)
->verificationChecks
->create($code, ['to' => $phoneNumber]);
if ($verificationCheck->status == 'approved')
{
// Code is correct. You can now mark the user as verified in your database.
echo json_encode(['success' => true, 'message' => 'Code approved!']);
}
else
{
echo json_encode(['success' => false, 'error' => 'Invalid code.']);
}
}
catch (Exception $e)
{
echo json_encode(['success' => false, 'error' => $e->getMessage()]);
}
}
else
{
echo json_encode(['success' => false, 'error' => 'Invalid request']);
}
?>
Sending verification codes to a phone number requires using a third-party service with an SMS or voice API (e.g., Twilio Verify API, Vonage Verify API, or Telesign VerifyClient), as PHP and JavaScript do not have built-in functionality to send text or voice messages directly.
Below is an example using the Vonage Verify API with a combination of HTML/JavaScript (frontend) and PHP (backend).
Implementing a verification system involves a frontend for user interaction (JavaScript/HTML) and a backend to securely handle API calls (PHP).
The Vonage Verify API is used on the server-side (PHP) to send the code and check the user's input, as API keys should never be exposed in frontend JavaScript code.
The frontend will collect the user's phone number, send it to a PHP script, and then collect the verification code.
File: index.html
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vonage Verification</title>
</head>
<body>
<h2>Send Verification Code</h2>
<form id="requestForm">
<label for="phoneNumber">Phone Number (E.164 format, e.g., +12025550101):</label>
<input type="text" id="phoneNumber" name="phoneNumber" required>
<button type="submit">Send Code</button>
</form>
<h2>Verify Code</h2>
<form id="verifyForm" style="display: none;">
<label for="code">Verification Code:</label>
<input type="text" id="code" name="code" required>
<input type="hidden" id="requestId" name="requestId">
<button type="submit">Verify</button>
</form>
<p id="status"></p>
<script>
document.getElementById('requestForm').addEventListener('submit', async (e) =>
{
e.preventDefault();
const phoneNumber = document.getElementById('phoneNumber').value;
const status = document.getElementById('status');
status.textContent = 'Sending code...';
const response = await fetch('request.php',
{
method: 'POST',
headers:
{
'Content-Type': 'application/json'
},
body: JSON.stringify({ phoneNumber })
}); // end response = await fetch()
const result = await response.json();
if (result.request_id)
{
document.getElementById('requestId').value = result.request_id;
document.getElementById('requestForm').style.display = 'none';
document.getElementById('verifyForm').style.display = 'block';
status.textContent = 'Code sent. Please enter it below.';
}
else
{
status.textContent = `Error: ${result.error_text || 'Something went wrong'}`;
}
}); // end document.getElementById('requestForm')
document.getElementById('verifyForm').addEventListener('submit', async (e) =>
{
e.preventDefault();
const code = document.getElementById('code').value;
const requestId = document.getElementById('requestId').value;
const status = document.getElementById('status');
status.textContent = 'Verifying code...';
const response = await fetch('verify.php',
{
method: 'POST',
headers:
{
'Content-Type': 'application/json'
},
body: JSON.stringify({ code, requestId })
}); // end response = await fetch()
const result = await response.json();
if (result.status === '0')
{
status.textContent = 'Verification successful!';
}
else
{
status.textContent = `Verification failed: ${result.error_text || 'Incorrect code'}`;
}
}); // end document.getElementById('verifyForm').addEventListener('submit', async (e) =>
</script>
</body>
</html>
You need the Vonage PHP client library. Install it using Composer: composer require vonage/client.
This script receives the phone number from the frontend and initiates the verification request using the Vonage Verify API. The API automatically handles the failover to a voice call if the SMS is not received.
File: request.php
<?php
require_once __DIR__ . '/vendor/autoload.php';
// Ensure you have your credentials defined in environment variables or replace with actual values
$apiKey = getenv('VONAGE_API_KEY') ?: 'YOUR_API_KEY';
$apiSecret = getenv('VONAGE_API_SECRET') ?: 'YOUR_API_SECRET';
$brandName = 'YourAppName'; // Replace with your brand name
$credentials = new Vonage\Client\Credentials\Basic($apiKey, $apiSecret);
$client = new Vonage\Client($credentials);
// Get the phone number from the POST request
$data = json_decode(file_get_contents('php://input'), true);
$phoneNumber = $data['phoneNumber'] ?? null;
if ($phoneNumber)
{
try
{
// The Verify v1 API automatically tries SMS first, then voice
$request = new \Vonage\Verify\Request($phoneNumber, $brandName);
$response = $client->verify()->start($request);
echo json_encode(['request_id' => $response->getRequestId(), 'status' => 'success']);
}
catch (Exception $e)
{
echo json_encode(['error_text' => $e->getMessage()]);
}
}
else
{
echo json_encode(['error_text' => 'Phone number missing']);
}
?>
This script checks the code provided by the user against the request_id from the previous step.
File: verify.php
<?php
require_once __DIR__ . '/vendor/autoload.php';
// Ensure you have your credentials defined in environment variables or replace with actual values
$apiKey = getenv('VONAGE_API_KEY') ?: 'YOUR_API_KEY';
$apiSecret = getenv('VONAGE_API_SECRET') ?: 'YOUR_API_SECRET';
$credentials = new Vonage\Client\Credentials\Basic($apiKey, $apiSecret);
$client = new Vonage\Client($credentials);
// Get the code and request ID from the POST request
$data = json_decode(file_get_contents('php://input'), true);
$code = $data['code'] ?? null;
$requestId = $data['requestId'] ?? null;
if ($code && $requestId)
{
try
{
$response = $client->verify()->check($requestId, $code);
// A status of '0' indicates a successful verification
if ($response->getStatus() === '0')
{
echo json_encode(['status' => '0', 'message' => 'Verification successful']);
}
else
{
echo json_encode(['status' => $response->getStatus(), 'error_text' => $response->getErrorText()]);
}
}
catch (Exception $e)
{
echo json_encode(['error_text' => $e->getMessage()]);
}
}
else
{
echo json_encode(['error_text' => 'Code or Request ID missing']);
}
?>
For more detailed information and the latest examples, consult the official Vonage API documentation.
To send a verification code via text or voice using a combination of PHP and JavaScript with the TeleSign Verify API, you need to use JavaScript on the client side to send the phone number to a backend PHP script via an asynchronous request (e.g., using Fetch or jQuery's $.post).
See the previous two examples on Twillio and Vonage APIs as a guide to help you implement this application using TeleSign API.
As a matter of fact, you can use the PHP script examples with your API credentials from TeleSign, then use the TeleSign PHP SDK to make the API call to send the message or voice call.
So I don't need to provide you another example application as it seems redundant and perhaps simple to do to accomplish the task.
The client-side code handles user input and makes an API call to your backend PHP script.
Sending a verification code via text message or voice message involves a combination of client-side JavaScript (to capture user input and make an asynchronous request) and server-side PHP (to securely handle authentication and interact with the TeleSign API).
The TeleSign PHP SDK installed via Composer in your project (composer require telesign/enterprise-sdk).
I'm a little too busy to provide a complete example, so I will refer you to their website and perhaps Google the TeleSign PHP SDK yourself and you'll get lots of information and tutorials.
To be continued!
Hierarchical data is a data structure that relates to a parent-child relation in the database. A simplier way of saying is that, a hierarchical data structure is simply a data structure organized as a tree, in which in a tree, there is a node or base tree (Food in the illustration below) and then the branching out of the limbs. For example, if we have some products organized as a tree of product category hierarchy from a fictional grocery store, the hierarchical data structure looks like the following:
As you can see from the illustration above, the hierarchical data structure runs top to bottom with Food as the parent (or base) node, and Fruit and Meat as the immediate children of Food.
We can say that Food is the parent of both Fruit and Meat; Fruit is the parent of Red and Yellow; Red is the parent of Cherry; Yellow is the parent of Banana.
Likewise, Meat is the parent of Beef and Pork.
See the table below which lists the parent-child relation.
The hierarchical data structure is one of the most common data structures in programming. It represents a set of data where each item (except the root) has one parent node and one or more children nodes. Web programmers use hierarchical data for a number of applications, including content management systems, forum threads, mailing lists, and e-commerce product categorization.
If you're programming social media commenting application similar to what you see in most web sites, you definitely need to use a hierarchical data structure to manage and display your users' post comments in a hierarchical data structure manner.
Answer: see the table below which lists the parent-child relation.
There are two hierarchical data models to manage hierarchical data structure. They are called adjacency list model and nested set model.
First of all, we need to create a table to store these parent-child relational data hierarchical structure.
<?php
CREATE TABLE category (
category_id INT(10) AUTO_INCREMENT PRIMARY KEY,
category_name VARCHAR(50) NOT NULL,
parent_id INT(10) DEFAULT NULL
);
?>
Now let's insert some dummy data into the above table definition. For example:
<?php
// insert data into the 'category' table
INSERT INTO category VALUES(1, 'Food', NULL), (2, 'Fruit', 1), (3, 'Red', 2),
(4, 'Cherry', 3), ( 5, 'Yellow', 2), (6, 'Banana', 5),
(7, 'Meat', 1), (8, 'Beef', 7), (9, 'Pork', 7),
(10, 'Fish', 1), (11, 'Sammon', 10), (12, 'Shrimp', 10),
(13, 'Walley', 10);
SELECT * FROM category ORDER BY category_id;
+-------------+----------------------+--------+
| category_id | name | parent |
+-------------+----------------------+--------+
| 1 | Food | NULL |
| 2 | Fruit | 1 |
| 3 | Red | 2 |
| 4 | Cherry | 3 |
| 5 | Yellow | 2 |
| 6 | Banana | 5 |
| 7 | Meat | 1 |
| 8 | Beef | 7 |
| 9 | Pork | 7 |
| 10 | Fish | 1 |
| 11 | Sammon | 10 |
| 12 | Shrimp | 10 |
| 13 | Walley | 10 |
+-------------+----------------------+--------+
10 rows in set (0.00 sec)
?>
In this tutorial, we'll be using MySQL and PHP to accomplish the task.
If you look at the table definition earlier and the output of the query order by category_id, the parent id (parent) is actually a category id (i.e., Food = 1, Fruit = 2, Meat = 7, Fish = 10) of the parent category (Food).
This listing of hierachical tree parent-child arrangment is quite simple; it is easy to see parent-child relations. Furthermore, the tree path (breadcrumb) can be generated using a simple PHP function. For example:
<?php
// you pass in a category id: fruit, meat, etc.
public function get_path($category_id)
{
// look up the parent of this node, if fruit, it is 'Food'
$result = mysql_query("SELECT c1.parent_id, c2.category_name AS parent_name FROM category AS c1
LEFT JOIN category AS c2 ON c1.parent_id = c2.category_id
WHERE c1.category_id = '$category_id' ");
$row = mysql_fetch_array($result);
// save the path in this array
$path = array();
//continue if this node is not the root node
if ($row['parent_id'] != NULL)
{
// set the last part of the path to node - point it back to node
// end() sets the internal pointer of an array to its last element
end($path);
$last_key = key($path);
$key = $last_key==0 ? 0 : $last_key+1;
$path[$key]['category_id'] = $row['parent_id'];
$path[$key]['category_name'] = $row['parent_name'];
$path = array_merge(get_path($row['parent_id']), $path);
}
return $path;
}
?>
To print the path, just do the following:
<?php
// iterate over all of the array elements
for ($i = count($path) - 1; $i == 0; $i--)
{
echo $path[$i]['category_name']. '>';
}
?>
<?php
// this function is a recursive function which is being called by itself below!
// depending on your application or objective, you might not need to call this function manually at all!
public function display_children($category_id, $level)
{
// retrieve all children
$sql = "SELECT * FROM category WHERE parent_id = '$category_id'";
$query = $conn->prepare($sql);
$result = $query->setFetchMode(PDO::FETCH__ASSOC);
// display each child
while ($row = $result->fetch())
{
// indent and display the title of the category_name of this child
// if you want to save the hierarchy, replace the following line with your code
echo str_repeat(' ', $level) . $row['category_name'] . "<br/>";
// call this function again to display this child's children
display_children($row['category_id'], $level + 1);
}
}
?>
The adjacency list model has its disadvantages. One of them is that, it is hard to implement it using only database queries. SQL queries require that you know at which level the node resides.
A much better and robust alternative is the nested set model for hierarchical data.
I'm little lazy, so I'm going to refer you to some excellent tutorials on the Web, which can explain better than I can. Here they are:
Managing Hierarchical Data in MySQL Handling Hierarchical Data in MySQL and PHPTo create a social media comment thread with hierarchical indentation in PHP, you typically use a recursive function. This function iterates through comments and calls itself to display replies based on a parent_id relationship stored in a database.
1. Database table structure.
First, you need a database table to store comments. The key to creating a hierarchical structure is the parent_id field, which references another comment's id. A parent_id of NULL or 0 indicates a top-level comment.
CREATE TABLE comments (
id INT(11) AUTO_INCREMENT PRIMARY KEY,
post_id INT(11) NOT NULL,
parent_id INT(11) DEFAULT NULL,
author VARCHAR(255) NOT NULL,
comment_text TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
2. Sample data.
Here is some sample data to illustrate the parent-child relationships.
INSERT INTO comments (id, post_id, parent_id, author, comment_text) VALUES (1, 123, NULL, 'Alice', 'This is a great post!'), (2, 123, 1, 'Bob', 'I agree, very insightful.'), (3, 123, NULL, 'Charlie', 'I have a different perspective on this topic.'), (4, 123, 2, 'Dave', 'Me too! The point about X was really strong.'), (5, 123, 3, 'Eve', 'That\'s an interesting take, Charlie.');
3. PHP recursive function.
The core of the solution is a recursive function that fetches and displays comments.
Explanation of the logic follows by the actual code:
* Fetch all comments: The script first fetches all comments for a specific post_id from the database.
* Reorganize into a tree: It then processes the flat array of comments into a nested array, or "tree," where each comment has a children property containing its replies. This is more efficient than running a new database query for every comment.
* Recursive function for display: The display_comment_recursive function takes the array of comments. It iterates through the comments and displays them. If a comment has children, it calls itself with the children's array, creating a nested display.
* Indentation with CSS: The depth parameter is used to add a CSS class (comment-depth-X) that creates the visual indentation.
File: index.php. This is your main website page or loading front page or the entry script page.
Notice that for illustration purposes and for easy to understand I chose to put all code in one file (index.php) -- this is called stacking -- stacking functions/and/or code on top of each other and it is perfectly legal and functional -- however, you can seperate them in different files for modularity purposes.
<?php
// 1. Database connection (replace with your credentials)
$servername = "localhost";
$username = "root";
$password = "";
$dbname = "your_database";
try
{
$pdo = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch (PDOException $e)
{
die("Connection failed: " . $e->getMessage());
}
// 2. Fetch all comments for a post
$post_id = 123;
$stmt = $pdo->prepare("SELECT * FROM comments WHERE post_id = ? ORDER BY created_at ASC");
$stmt->execute([$post_id]);
$all_comments = $stmt->fetchAll(PDO::FETCH_ASSOC);
// 3. Build a hierarchical tree from the flat comment list
function comment_tree(array $comments, $parentId = NULL)
{
$branch = [];
foreach ($comments as $comment)
{
if ($comment['parent_id'] == $parentId)
{
$children = comment_tree($comments, $comment['id']);
if ($children)
{
$comment['children'] = $children;
}
$branch[] = $comment;
}
}
return $branch;
}
// calling function comment_tree() (above) passing the fetched users comments $all_comments from (above) as an argument
$comment_tree = comment_tree($all_comments);
// 4. Recursive function to display the comments
// $comments got passed in as argument from $comment_tree (above)
function display_comment_recursive($comments, $depth = 0)
{
echo '<ul class="comment-list ' . ($depth > 0 ? 'nested-comments' : '') . '">';
foreach ($comments as $comment)
{
echo '<li class="comment comment-depth-' . $depth . '">';
echo '<div class="comment-meta">';
echo '<strong>' . htmlspecialchars($comment['author']) . '</strong> ';
echo '<span>' . date('M j, Y', strtotime($comment['created_at'])) . '</span>';
echo '</div>';
echo '<div class="comment-text">' . htmlspecialchars($comment['comment_text']) . '</div>';
// Add a reply link (optional)
echo '<a href="#reply-to-' . $comment['id'] . '">Reply</a>';
// Recursively call for children
if (isset($comment['children']))
{
display_comment_recursive($comment['children'], $depth + 1);
}
echo '</li>';
}
echo '</ul>';
}
?>
Note that the following HTML is part of the index.php file (above) -- this is called stacking!
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Social Media Comment Thread</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<h1>Comments</h1>
<div class="comment-section">
<!-- get the ball rolling by calling the recursive function -->
<?php display_comment_recursive($comment_tree); ?>
</div>
</body>
</html>
This is the end of index.php file!
4. CSS for indentation.
You can use CSS to apply left margins based on the depth class created by the PHP function.
File: style.css (This file is not part of index.php above but rather a seperate css file)
body {
font-family: Arial, sans-serif;
line-height: 1.6;
margin: 20px;
}
.comment-section {
max-width: 800px;
margin: 0 auto;
}
.comment-list {
list-style: none;
padding: 0;
margin: 0;
}
.comment {
border: 1px solid #ddd;
border-radius: 5px;
padding: 15px;
margin-bottom: 10px;
}
/* Indentation based on depth */
.comment-depth-1 {
margin-left: 30px;
}
.comment-depth-2 {
margin-left: 60px;
}
.comment-depth-3 {
margin-left: 90px;
}
/* Add more depths as needed */
.comment-meta {
font-size: 0.9em;
color: #555;
margin-bottom: 5px;
}
.comment-text {
margin-bottom: 10px;
}
.comment a {
color: #007bff;
text-decoration: none;
}
To create a hierarchical, indented comment thread with a "reply" button using PHP, you will need a database, a recursive function to fetch and display the comments, and some JavaScript to handle the reply form dynamically.
1. Database structure.
The core of a threaded comment system is a database table with a parent_id column that references the id of another comment in the same table. A NULL or 0 value in the parent_id indicates a top-level comment.
CREATE TABLE `comments` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`post_id` int(11) NOT NULL,
`parent_id` int(11) DEFAULT NULL,
`author` varchar(255) NOT NULL,
`comment_text` text NOT NULL,
`created_at` datetime NOT NULL DEFAULT current_timestamp(),
PRIMARY KEY (`id`),
KEY `post_id` (`post_id`),
KEY `parent_id` (`parent_id`)
);
2. PHP code.
Notice that for illustration purposes and for easy to understand I chose to put some of code in one file (index.php) -- this is called stacking -- stacking functions/and/or code on top of each other and it is perfectly legal and functional -- however, you can seperate them in different files for modularity purposes like db_connect.php and comment_functions.php.
File: index.php (or your main post page)
This file fetches all the comments for a specific post, structures them into a hierarchical array, and then passes them to the display function.
<?php // Include your database connection and functions include 'db_connect.php'; include 'comment_functions.php'; $post_id = 1; // Example: The ID of the post // Fetch all comments for the post $sql = "SELECT * FROM comments WHERE post_id = ? ORDER BY created_at ASC"; $stmt = $pdo->prepare($sql); $stmt->execute([$post_id]); $all_comments = $stmt->fetchAll(PDO::FETCH_ASSOC); // Create a hierarchical array $comment_tree = buildCommentTree($all_comments, null); ?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Comment Thread Example</title>
<style>
body
{
font-family: sans-serif;
}
.comment
{
margin: 15px 0; border-left: 2px solid #ddd; padding-left: 15px;
}
.comment .meta
{
font-size: 0.9em; color: #555;
}
.comment .reply-button
{
cursor: pointer; color: #007bff; text-decoration: underline; margin-left: 10px;
}
.comment .comment-content
{
margin: 5px 0;
}
.reply-form
{
margin-top: 10px; display: none;
}
.reply-form textarea
{
width: 100%; height: 60px;
}
.replies
{
margin-left: 30px;
}
</style>
</head>
<body>
<h1>Post Title</h1>
<p>This is the content of the post.
<h2>Comments</h2>
<!-- get the ball rolling by calling function displayComments() -->
<?php displayComments($comment_tree); ?>
<h3>Leave a Comment</h3>
<form action="submit_comment.php" method="post">
<input type="hidden" name="post_id" value="<?php echo $post_id; ?>">
<input type="hidden" name="parent_id" value="0" id="parent-comment-id">
<input type="text" name="author" placeholder="Your Name" required><br>
<textarea name="comment_text" placeholder="Your Comment" required></textarea><br>
<button type="submit">Submit Comment</button>
</form>
<script src="script.js"></script>
</body>
</html>
File: comment_functions.php
This file contains the recursive functions for building and displaying the comments.
<?php
// buildCommentTree(): Recursively organizes comments into a nested array
function buildCommentTree(array $elements, $parentId = null)
{
$branch = [];
foreach ($elements as $element)
{
if ($element['parent_id'] == $parentId)
{
$children = buildCommentTree($elements, $element['id']);
if ($children)
{
$element['children'] = $children;
}
$branch[] = $element;
}
}
return $branch;
}
// displayComments(): Recursively outputs the comment tree as HTML
function displayComments(array $comments)
{
foreach ($comments as $comment)
{
echo '<div class="comment" data-comment-id="' . htmlspecialchars($comment['id']) . '">';
echo '<div class="meta"><strong>' . htmlspecialchars($comment['author']) . '</strong> - ' .
htmlspecialchars($comment['created_at']) . '</div>';
echo '<div class="comment-content">' . htmlspecialchars($comment['comment_text']) . '</div>';
echo '<button class="reply-button">Reply</button>';
// Display reply form for this comment
echo '<div class="reply-form">';
echo '<form action="submit_comment.php" method="post">';
echo '<input type="hidden" name="post_id" value="' . htmlspecialchars($comment['post_id']) . '">';
echo '<input type="hidden" name="parent_id" value="' . htmlspecialchars($comment['id']) . '">';
echo '<input type="text" name="author" placeholder="Your Name" required><br>';
echo '<textarea name="comment_text" placeholder="Your Reply" required></textarea><br>';
echo '<button type="submit">Submit Reply</button>';
echo '</form>';
echo '</div>'; // .reply-form
// Recursively display nested replies
if (!empty($comment['children']))
{
echo '<div class="replies">';
// recursively calling itself to display the children
displayComments($comment['children']);
echo '</div>'; // .replies
}
echo '</div>'; // .comment
}
}
?>
3. JavaScript to handle replies.
Use JavaScript to toggle the visibility of the reply form when a "Reply" button is clicked.
javascript:
// script.js
document.addEventListener('DOMContentLoaded', function()
{
document.querySelectorAll('.reply-button').forEach(button =>
{
button.addEventListener('click', function()
{
const comment = this.closest('.comment');
const replyForm = comment.querySelector('.reply-form');
replyForm.style.display = (replyForm.style.display === 'block') ? 'none' : 'block';
});
});
});
4. Handling form submission.
File: submit_comment.php.
This script handles the insertion of new comments and replies into the database.
<?php
include 'db_connect.php';
if ($_SERVER['REQUEST_METHOD'] === 'POST')
{
// this is equivalent to older version (pre-PHP 7): $post_id = isset($_POST['post_id']) ? $_POST['post_id'] : null;
$post_id = $_POST['post_id'] ?? null;
$parent_id = $_POST['parent_id'] ?? null;
$author = $_POST['author'] ?? null;
$comment_text = $_POST['comment_text'] ?? null;
if ($post_id && $author && $comment_text)
{
$sql = "INSERT INTO comments (post_id, parent_id, author, comment_text) VALUES (?, ?, ?, ?)";
$stmt = $pdo->prepare($sql);
$stmt->execute([$post_id, $parent_id, $author, $comment_text]);
// Redirect back to the original page
header("Location: index.php?post_id=" . $post_id);
exit();
}
}
?>
How it works.
Database: Each comment is stored with a parent_id linking it to its parent comment. A NULL parent_id denotes a top-level comment.
PHP: The buildCommentTree() function recursively converts the flat list of comments from the database into a nested array structure. The displayComments() function then traverses this nested array, outputting HTML for each comment.
Indentation: The HTML output uses nested <div>s, and a simple CSS rule indents replies by applying a left margin to the .replies container.
Reply Button: The "Reply" button is a simple HTML button.
JavaScript: The JavaScript code listens for clicks on any "Reply" button and toggles the visibility of the corresponding reply form, ensuring the correct parent_id is automatically populated.
End of example 2.
Implementing a social media-style hierarchical comment thread with reply buttons and an approval workflow in PHP involves several key components: database design, front-end rendering, and back-end logic for submission and approval.
Notice that for illustration purposes and for easy to understand I chose to seperate the various parts of the code logic in different files for modularity purposes. This is the typical way of programming. You'll have to customize and add other code logic accordingly.
1. Database Design:
A comments table would typically include:
id: Primary key.
post_id: Foreign key to the post the comment belongs to.
user_id: Foreign key to the user who posted the comment.
parent_id: Foreign key to the parent comment's id for replies (NULL for top-level comments).
comment_text: The content of the comment.
created_at: Timestamp of creation.
status: pending, approved, rejected for approval workflow.
2. Front-End Rendering (PHP & HTML):
To display hierarchical comments, a recursive function or an iterative approach with depth tracking is used.
<?php
function displayComments($comments, $parentId = null, $depth = 0)
{
echo '<ul style="padding-left: ' . ($depth * 20) . 'px;">'; // Indentation
foreach ($comments as $comment)
{
if ($comment['parent_id'] == $parentId)
{
echo '<li>';
echo '<p>' . htmlspecialchars($comment['comment_text']) . '</p>';
if ($comment['status'] == 'approved')
{
echo '<button class="reply-button" data-comment-id="' . $comment['id'] . '">Reply</button>';
}
else
{
echo '<p>Comment awaiting approval.</p>';
}
// Reply form (initially hidden)
echo '<div id="reply-form-' . $comment['id'] . '" style="display:none;">';
echo '<form action="submit_comment.php" method="POST">';
echo '<textarea name="comment_text"></textarea>';
echo '<input type="hidden" name="parent_id" value="' . $comment['id'] . '">';
echo '<input type="hidden" name="post_id" value="' . $comment['post_id'] . '">';
echo '<button type="submit">Submit Reply</button>';
echo '</form>';
echo '</div>';
displayComments($comments, $comment['id'], $depth + 1); // Recursively display replies
echo '</li>';
}
}
echo '</ul>';
}
// Example usage (assuming $allComments is an array of comments from the database)
// See a similar code at the top of example 2 that looks like this: $all_comments = $stmt->fetchAll(PDO::FETCH_ASSOC);
// displayComments($allComments);
?>
<script>
document.querySelectorAll('.reply-button').forEach(button =>
{
button.addEventListener('click', function()
{
const commentId = this.dataset.commentId;
const replyForm = document.getElementById('reply-form-' + commentId);
if (replyForm.style.display === 'none')
{
replyForm.style.display = 'block';
}
else
{
replyForm.style.display = 'none';
}
});
});
</script>
3. Back-End Logic (PHP):
File: submit_comment.php:
<?php
// Database connection (e.g., PDO)
$pdo = new PDO('mysql:host=localhost;dbname=your_db', 'username', 'password');
if ($_SERVER['REQUEST_METHOD'] === 'POST')
{
$commentText = $_POST['comment_text'];
$postId = $_POST['post_id'];
$parentId = isset($_POST['parent_id']) ? $_POST['parent_id'] : null;
$userId = 1; // Replace with actual logged-in user ID
$stmt = $pdo->prepare("INSERT INTO comments (post_id, user_id, parent_id, comment_text, status)
VALUES (?, ?, ?, ?, 'pending')");
$stmt->execute([$postId, $userId, $parentId, $commentText]);
header('Location: post_page.php?id=' . $postId); // Redirect back to post
exit();
}
?>
File: admin_approval.php (for comment approval workflow):
<?php
// Database connection
$pdo = new PDO('mysql:host=localhost;dbname=your_db', 'username', 'password');
// Fetch pending comments
$stmt = $pdo->query("SELECT * FROM comments WHERE status = 'pending' ORDER BY created_at ASC");
$pendingComments = $stmt->fetchAll(PDO::FETCH_ASSOC);
echo '<h1>Pending Comments for Approval</h1>';
foreach ($pendingComments as $comment)
{
echo '<p>' . htmlspecialchars($comment['comment_text']) . ' (User ID: ' . $comment['user_id'] . ')</p>';
echo '<form action="admin_approval.php" method="POST" style="display:inline;">';
echo '<input type="hidden" name="comment_id" value="' . $comment['id'] . '">';
echo '<button type="submit" name="action" value="approve">Approve</button>';
echo '</form>';
echo '<form action="admin_approval.php" method="POST" style="display:inline;">';
echo '<input type="hidden" name="comment_id" value="' . $comment['id'] . '">';
echo '<button type="submit" name="action" value="reject">Reject</button>';
echo '</form>';
echo '<hr>';
}
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']))
{
$commentId = $_POST['comment_id'];
$action = $_POST['action'];
$newStatus = ($action === 'approve') ? 'approved' : 'rejected';
$stmt = $pdo->prepare("UPDATE comments SET status = ? WHERE id = ?");
$stmt->execute([$newStatus, $commentId]);
header('Location: admin_approval.php'); // Refresh approval page
exit();
}
?>
You can customize/add more features and capabilities accordingly to suite your objective.
That is it!
Disclaimer and credit: I wrote this book right around 2004-5 when ajax was just catching fire when people were talking about ajax as if it was the second coming of the birth of the internet. Yes, it was all the rage for quite some time in those days and continued for much of the first half of the millenial decade (up to 2015).
Now into the post millenial decade (starting in 2020 and beyond) it dies down quite a bit, but ajax is still very much relevant in today's programming and will still be quite relevant to the future as well.
Also, much of the materials in this book were based on articles written by my fellow Twin Citian native Brett McLaughlin of Saint Paul, Minnesota. Without the articles it wouldn't have been possible to write this book. I wouldn't know where to start, let alone finish the entire book. Needless to say, the articles were clearly acted as road maps for this book.
Ajax, which stands for Asynchronous JavaScript and XML, isn't a single technology or a conforming programming language like Pascal, Delphi, Java, C/C++, PHP, JavaScript, etc, but it's a Web development technique that includes the following:Before I dig into what Ajax is, though, let's spend just a few moments understanding what Ajax does. When you write an application today (and as well as in the future), you have two basic choices (well, maybe three - mobile is the other one - but the core basic technology is just two: desktop and web):
These are both familiar; desktop applications usually come on a CD (or sometimes are downloaded from a Web site) and install completely on your computer. They might use the Internet to download updates, but the code that runs these applications resides on your desktop. Web applications -- and there's no surprise here -- run on a Web server somewhere and you access the application with your Web browser.
More important than where the code for these applications runs, though, is how the applications behave and how you interact with them. Desktop applications are usually pretty fast (they're running on your computer; you're not waiting on an Internet connection), have great user interfaces (usually interacting with your operating system), and are incredibly dynamic. You can click, point, type, pull up menus and sub-menus, and cruise around, with almost no waiting around.
On the other hand, Web applications are usually up-to-the-second current and they provide services you could never get on your desktop (think about Amazon.com and eBay). However, with the power of the Web comes waiting -- waiting for a server to respond, waiting for a screen to refresh, waiting for a request to come back and generate a new page.
Obviously this is a bit of an oversimplification, but you get the basic idea. As you might already be suspecting, Ajax attempts to bridge the gap between the functionality and interactivity of a desktop application and the always-updated Web application. You can use dynamic user interfaces and fancier controls like you'd find on a desktop application, but it's available to you on a Web application.
Chapter 1
Ajax Basics Tutorial
Section 1.1: Introduction
Ajax, which consists of HTML, JavaScript, DHTML, CSS, XSLT, and DOM, is an outstanding approach that helps you transform clunky Web interfaces into interactive Ajax applications. This book will demonstrate how these technologies [HTML, JavaScript, DHTML, and DOM] work together -- from an overview to a detailed look -- to make extremely efficient Web development an easy reality. The book also unveil the central concepts of Ajax, including the XMLHttpRequest object.
Ajax works by combining several technologies to function in a seamlessly intuitive manner. Instead of loading a Web page at the start of a session, the browser loads an Ajax engine, written in JavaScript and usually tucked away in a hidden frame. This Ajax engine is responsible for both rendering the interface the user sees and communicating with the server on the user's behalf.
The Ajax engine allows the user's interaction with the application to happen asynchronously -- independent of communication with the server. Every user action that would normally generate an HTTP request takes the form of a JavaScript call to the Ajax engine instead. Any response to a user action that doesn't require a trip back to the server -- such as simple data validation, editing data in memory and even some navagation -- the engine handles on its own.
If the engine needs something from the server in order to respond -- if it's submitting data for processing, loading additional interface code or retrieving new data -- it makes those requests asynchronously, usually using XML, without stalling a user's interaction with the application.
Old technology, new tricks
When it comes to Ajax, the reality is that it involves a lot of technologies -- to get beyond the basics, you need to drill down into several different technologies (as outlined in the introduction at the beginning of this book). The good news is that you might already know a decent bit about many of these technologies -- and better yet, most of these individual technologies (such as HTML, XHML, JavaScript, XML, CSS, etc) are easy to learn -- certainly not as difficult as an entire programming language like Pascal, Delphi, Java, C/C++, PHP, JavaScript, Ruby, etc.
|
Here (again) are the basic technologies involved in Ajax applications:
div, span, and
other dynamic HTML elements to mark up your HTML. Let's break these down and get a better idea of what each does. I'll delve into each of these more in coming sections; for now focus on becoming familiar with these components and technologies. The more familiar you are with this code, the easier it will be to move from casual knowledge about these technologies to mastering each (and really blowing the doors off of your Web application development).
Section 1.2: The XMLHttpRequest Object
<script language="javascript" type="text/javascript">
var xmlHttp = new XMLHttpRequest();
</script>
|
<script language="javascript" type="text/javascript">
// Get the value of the "phone" field and stuff it in a variable called phone
let phone = document.getElementById("phone").value;
// Set some values on a form using an array called response
// don't worry if you don't understand the assigning of array
// value response to variables order and address.
// It will be explained a little bit later.
// For example: response = obj.responseText;
document.getElementById("order").value = response[0];
document.getElementById("address").value = response[1];
</script>
|
<script language="javascript" type="text/javascript">
var xmlHttp = false;
try
{
xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
}
catch (e)
{
try
{
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
}
catch (e2)
{
xmlHttp = false;
}
}
</script>
|
<script language="javascript" type="text/javascript">
/* Create a new XMLHttpRequest object to talk to the Web server */
var xmlHttp = false();
/*@cc_on @*/
/*@if (@_jscript_version >= 5)
try
{
//try to create one of Microsoft's older browser version
xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
}
catch (e)
{
try
{
//the above code fail, so try to create a new version of MS browser
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
}
catch (e2)
{
xmlHttp = false;
}
}
@end @*/
if (!xmlHttp && typeof XMLHttpRequest != 'undefined')
{
//No MS browser found, so create a non-MS multi-browsers object
xmlHttp = new XMLHttpRequest();
}
</script>
|
For now, ignore the commenting and weird tags like @cc_on; those are special JavaScript compiler commands (called directives) which directs the flow of code to specific block. In this case, it basically says that if one of Microsoft's browser versions is found, don't execute the non-Microsoft browsers block of code. You'll learn more about compiler directives as you progress deeper into this book. For now, let's continue with our XMLHttpRequest discussion. The core of this code breaks down into three steps:
|
Today's browsers offer users the ability to crank their security levels up, to turn off JavaScript technology, and disable any number of options in their browser. In these cases, your code probably won't work under any circumstances. For these situations, you'll have to handle problems gracefully -- that's at least one section of topic in itself, one I will tackle later in this book. For now, you're writing robust, but not perfect, code, which is great for getting a handle on Ajax. You'll come back to the finer details later. |
<script language="javascript" type="text/javascript">
/* Create a new XMLHttpRequest object to talk to the Web server */
var xmlHttp = false;
if (document.window.XMLHttpRequest)
{
//creating a non-MS browser object
xmlHttp = new XMLHttpRequest();
}
else if (document.window.ActiveXObject)
{
// this is the newer MS browser object and not even
// bother to test for older versions.
// not only that Microsoft has dropped the other older
// version completely and is rallying around this new
// enhanced, up-to-date version.
// so Microsoft is maintaining this version to the
// distance future.
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
}
else
{
document.write("unknown browser");
}
</script>
|
<html>
<head>
<title>Browser Initialization</title>
<script language="JavaScript" type="text/javascript">
function getxmlHttp()
{
/* Create a new XMLHttpRequest object to talk to the Web server */
var xmlHttp = false;
if (document.window.XMLHttpRequest)
{
//creating a non-MS browser object
xmlHttp = new XMLHttpRequest();
}
else if (document.window.ActiveXObject)
{
// this is the newer MS browser object and not even
// bother to test for older versions
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
}
else
{
document.write("unknown browser");
}
}
// Now, you can call this function just once in every program to create an
// object. Ignore some of the ready states for now; it will be discussed shortly.
// Notice also the var declaration to signify as a global variable.
var obj = getxmlHttp(); // create an object defined above
// Create the callback:
obj.onreadystatechange = function()
{
if (obj.readyState != 4)
{
return; // Nothing is returned ... not ready state yet
}
if (obj.status != 200)
{
// Returns nothing ... handle request failure here...
return;
}
// Request successful, read the response
var response = obj.responseText;
// Here you do whatever you need to do with response variable ...
}
</script>
</head>
</html>
|
<html>
<head>
<title>Browser Initialization</title>
<script language="JavaScript" type="text/javascript">
function getxmlHttp()
{
/* Create a new XMLHttpRequest object to talk to the Web server */
var xmlHttp = false;
if (document.window.XMLHttpRequest)
{
//creating a Firefox, Safari, and other non-MS browser objects
xmlHttp = new XMLHttpRequest();
}
else if (document.window.ActiveXObject)
{
// this is the newer MS browser object and not even
// bother to test for older versions
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
}
else
{
document.write("unknown browser");
}
return xmlHttp;
}
// Now, you can call this function just once in every program to create an
// object. Ignore some of the ready states for now; it will be discussed shortly:
var obj = getxmlHttp(); // create an object defined above
// Create the callback:
obj.onreadystatechange = function()
{
if (obj.readyState != 4)
{
return; // Nothing is returned ... not ready state yet
}
if (obj.status != 200)
{
// Returns nothing ... handle request failure here...
return;
}
// Request successful, read the response
var response = obj.responseText;
// Here you do whatever you need to do with response variable ...
}
</script>
</head>
</html>
|
<script language="javascript" type="text/javascript">
function callServer()
{
let xmlHttp = new XMLHttpRequest();
// Get the city and state from the web form
let city = document.getElementById("city").value;
let state = document.getElementById("state").value;
// Only go on if there are values for both fields
if ((city == null) || (city == ""))
return;
if ((state == null) || (state == ""))
return;
// Build the URL to connect to
let url = "/script/getZipCode.php?city=" + escape(city) +
"&state=" + escape(state);
// Open a connection to the server
xmlHttp.open("GET", url, true);
// Setup a function for the server to run when it's done
xmlHttp.onreadystatechange = updatePage;
// Send the request
xmlHttp.send(null);
}
</script>
|
A lot of this is self-explanatory. The first bit of the code uses basic JavaScript code to grab the values of a few form fields. getElementById() is a JavaScript method that stores/returns a form field. In PHP, this (getElementById()) method is equivalent to the global variable _POST[], _GET[], or _REQUEST, which grabs the values of a few form fields. Next, it constructs a url to connect to the server.
Please note that you need to use a complete url of the remote host you're trying to connect to, such as http://www.remotehostexample.com/. And as well as any folder/directory names followed by the script name. For example, http://www.remotehostexample.com/local_folder/scriptname.php. The example url's shown in this book omit the full and proper url details. Self-explanatory!
More about the JavaScript getElementById() method. The variable name inside the double quotes ("....") is the field name of the input field. For example, the city, state, phone, email, username fields are listed in the input fields of the form as follows:
<script language="javascript" type="text/javascript">
function updatePage()
{
if (xmlHttp.readyState == 4)
{
let response = xmlHttp.responseText;
document.getElementById("zipCode").value = response;
}
}
</script>
|
<HTML>
<form>
<p>City: <input type="text" name="city" id="city" size="25"
onChange="callServer();" /></p>
<p>State: <input type="text" name="state" id="state" size="25"
onChange="callServer();" /></p>
<p>Zip Code: <input type="text" name="zipCode" id="zipCode" size="5" /></p>
</form>
</HTML>
|
If this feels like yet one more piece of fairly routine code, then you're right -- it is! There is nothing special about the code shown thus far. When a user puts in a new value for either the city or state field, the callServer() method fires off and the Ajax engine begins.
Notice also that the form doesn't contain the usual 'method' attribute, which is for specifying either a GET or a POST request. And the form doesn't even contain the important attribute called action for specifying the url to send the form to for processing. What is going on?
Well, the form doesn't need any of those two attributes in an Ajax world because all of the required attributes are being done in the callServer() method. And as stated above, the form doesn't contain a submit button to press to send the form to the server either.
If you look back at the beginning of this section 1.4, you'll see this callServer() method does all the work of specifying the two attributes and everything else that needed to be done. This is the heart and soul of Ajax.
Section 1.5: A touch of jQueryA request/response model can be accomplished using jQuery and cURL as well. We'll tackle a request/response model using cURL in the next section. But first, in this section, we'll illustrate the request/response model using jQuery.
Please check out the complete guide at the site: jQuery Ajax
The following is just a brief tutorial on the subject of jQuery Ajax.
<?php
/**
* here, it starts with '$' -- the jquery variable
* next, it calls the jquery function: ajax()
* this is the main jquery function similar to XMLHttpRequest() in Ajax
*
* just like any other programming languages, jquery has many functions at
* its disposable. please check out the guide mention above to learn more.
*
* just like XMLHttpRequest() in Ajax, jquery's ajax() function gets used on
* virtually every script you write. it's the core central function of jquery.
*
* if you look in the example below, you'll see two funtions: ajax() and done()
*
* all jquery scripts must start with ajax() function and if you have more
* functions they have to be chained to the ajax() function one after another.
*
* as you can see below, function done() is chained to function ajax() using
* the dot '.' notation.
* inside the function ajax() is where you do all of the request/response model.
*
* likewise, inside function done() is where you do all of your finishing code.
*
* inside any function contains an array denoted by {}, similar to json array: {}
*
* casual observer would notice that curly brackets are being used as an array and
* as a body of the function as well.
*
* if you look inside ajax() it contains blocks of code surrounded by the array {}
* this is the array using curly brackets {} similar to json array: {}
*
* on the other hand, a function, including ajax(), can contain other (anonymous)
* functions as well.
*
* you already know that any function, including anonymous functions, must contain
* a body of a function, which is denoted by {} brackets.
*
* this is shouldn't be a surprise to any of you.
*
* inside ajax() it contains blocks of code surrounded by the array {} but with
* some exceptions. for example, url and content are two examples of exceptions,
* in this case.
*
* url is the url of the remote host that you want to connect to.
* beforeSend is the code block you do before you send it to the server, such as
* code initialization of the header.
*
* content block contains the content that you want to send to the server.
* please check out the guide to learn more about these and others as well.
*/
$.ajax(
{
/* notice that {} denote as an array */
/* actually jquery adopts a json programming construct using curly */
/* brackets {} to denote as an array construct */
/* basically, ajax() function contains an array, for example: ajax({}) */
/* the curly brackets {} denote as an array construct */
/* if look closely inside the {}, you'll see key/value pairs which constitute */
/* as an array construct and sometimes multi-dimension array construct. */
/* as you can see, 'url' is the array key and the right side of ":" is the value. */
/* likewise, 'beforeSend' is the key and the anonymous function is the value */
/* did I mention somewhere this website that Javascript language is the */
/* most difficult to learn? */
/* all of these code are Javascript code. Jquery is a descendant of Javascript. */
/* okay, try to make sense of the code in the ajax() function on your own: */
url: "https://www.example.com/test.php",
/* no curly brackets {} except for the function beforeSend */
beforeSend: function( xhr )
{
xhr.overrideMimeType( "text/plain; charset=x-user-defined" );
},
/* notice that you can omit the curly brackets {} as well */
/* well, think of it this way: it's a key/value pair */
context: document.body,
/* no curly brackets {} except for the function success */
/* well, think of it this way: it's a key/value pair */
success: function (data, status, xhr)
{
// success callback function being displayed to the paragraph tag <p>
$('p').append(data);
},
/* no curly brackets {} except for the function error */
/* well, think of it this way: it's a key/value pair */
error: function (jqXhr, textStatus, errorMessage)
{
// error callback being displayed to the paragraph tag <p>
$('p').append('Error: ' + errorMessage);
},
/* notice the curly brackets {} are being used */
/* well, think of it this way: it's a key/value pair */
statusCode:
{
404: function()
{
alert( "page not found" );
}
}
).done(function()
{
$( this ).addClass( "done" );
}
);
// Or it can be written as the following.
// Notice that both ajax() and done() are aligned at the same indentation.
// I prefer this style better moving the chain dot '.' to the beginning line.
// It's much mor cleaner when code gets lengthy and complex!
$.ajax(
{
url: "test.html",
context: document.body
}
)
.done(function()
{
$( this ).addClass( "done" );
}
);
// notice that done() function is chained to the ajax() function and
// if you have more functions, they have to be chained one after another
// following ajax() function.
?>
Again, this is just a brief overview of the request/response model using jQuery. For more check out the guide mentioned earlier.
Section 1.6: A touch of cURLIn the previous sections we saw a request/response model using Ajax and jQuery; and in this section, we'll see how cURL can be used as a request/response model to transfer data just like Ajax and jQuery.
Please note that this is just a brief overview of the request/response model using cURL. For more, please check out my tutorial called an introduction to cURL and as well as the guides/tutorials on the web.
cURL (or client URL) is a request/response model or protocal that enables to send and receive data to and from the server. In other words, you can use cURL to transfer data to the server and the server will return the data you requested back to you (or more specifically, your client application, hence the word client in cURL). It's a request/response transfer protocol or model!
Typically, you made a request to the server using a client-side programming language like Javascript and then you need a server-side script like PHP to response to it and parse it and process it and then send back the response to the client.
But in a cURL script, it is a server-side language PHP acting as a client-side script using cURL to make a request to the server-side language like PHP. Make note: PHP is making a request to a server-side language PHP.
So PHP is sort of both a server-side and a client-side language -- making use CURL, which stands for "Client URL", as a client-side language.
Now the whole examples below are making some requests to server scripts (in the below cases: some_remote_file.html and www.ladygaga.com).
These two files (some_remote_file.html and www.ladygaga.com) are server-side scripts that reside in the servers somewhere. You could rename this some_remote_file.html to some_remote_file.php and it will work just fine. And you could add a server-side script to this file www.ladygaga.com as www.ladaygaga.com/myscript.php and it will executes myscript.php and it will work just fine.
So the point is: PHP is sort of both a server-side and a client-side language -- making use cURL to enable as a client-side language.
You will encounter that cURL is a very popular usage among financial transactions (such as credit card transactions) used by payment processing companies like Visa, Mastercard, PayPal, Stripe, and Authorize.NET, etc.
To transfer data using cURL or to fetch/retrieve data using cURL, you have to write a client script using client-side script called cURL and a server-side language like PHP to response to the client-side language.
In other words, to make a request to the server you use PHP script that makes use cURL, and to response to cURL script, you use PHP script (which is a server-side script) to send back the content requested by the client script.
Do you see what's going on here?
PHP is sort of both a server-side and a client-side language -- making use cURL to enable as a client-side language.
In this tutorial, we'll use PHP as the server-side scripting language to response to the client-side language cURL.
Let's see some examples with explanations accompanying the illustration. Let's try to retrieve the content of a remote website: any content that appears on the remote website, it's a fair game!
All we need is the url of the remote website and we can get all of the content in the remote website.
In order to download the contents of a remote web site, we need to define the following options:
CURLOPT_RETURNTRANSFER: Enables the assignment of the data that we download from the remote site to a variable, i.e., $result. When we print the value of the variable $result to the screen, we will see the picture/content of a web site being displayed.
The options can be written more compactly using curl_setopt_array(), which is a cURL function that convenes the options into an array.
Okay, let's putting things together. Notice that this example shows a very minimal options that are available. There are lots of options available to set, but for the sake of simplicity, we'll just use the very absolute minimum options. But first, here is a typical skeleton of the cURL script:
<?php
$url = __DIR__ . DIRECTORY_SEPARATOR . "some_remote_file.html";
/**
* initializing curl.
* this is like creating a constructor in other programming
* languages. when this line is executed it will go through a
* series of code initialization.
*
* remember a constructor in other programming languages is an "empty"
* function that contains nothing! no code! nothing!
* as you can see below, it contains nothing!
* this is by design so that you can put initialization code inside it so
* it can execute your code to initialize it! simple enough!
*
* if you look closely below, you'll see code like this: curl_setopt_array($curl, [])
* you provide the code to initialize contains in the array construct []
* curl_setopt_array() is an array and it will pair the two arguments and goes to work
* to initialize the code you provide in the array construct []
*/
$curl = curl_init();
/**
* after all of initialization has been done, it opens a
* connection to the url you provided in variable $url.
* the 'w' is to signify to the file protocol that we want
* to send (or 'w'rite to) the remote file (or website).
*/
$fileHandle = fopen($url, "w");
/**
* CURLOPT_URL is the option containing the remote url.
*
* CURLOPT_HEADER is the option containing the client header,
* the header that this browser sends to the remote host.
*
* CURLOPT_RETURNTRANSFER is the option to specify that we
* want cURL to return the requested content back to us.
* setting CURLOPT_RETURNTRANSFER to true does the job.
*
* sometimes, we just want to send the content to the
* remote host and never want to get anything back; for example,
* when you connect to a remote host to use its API services
* such as using PayPal credit card payment API, Stripe credit card
* payment API or a stock trading API from some of the brokerage services,
* you don't need to receive the content back through this client
* request initiation.
*
* instead, you just want to connect to the remote host and access their
* API content that is storing in the remote host's server.
*
* in that case, set it to false because you don't want the server to
* send back the whole API content via the internet.
* besides, the remote host would not allow you to do that in the first place.
*
* CURLOPT_FILE option is to allow us to send and receive
* files. in cURL, we can send any content including
* files. using CURLOPT_FILE option allow us to send and
* receive files.
*/
curl_setopt_array($curl, [
CURLOPT_URL => $url,
CURLOPT_HEADER => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FILE => $fileHandle
]
);
/**
* after all of options have been set, it's time to
* send the request to cURL to do its job.
*
* if you think of it, cURL is like other languages where they have classes.
* classes have three attributes: 1st, 2nd, 3rd, but cURL has two attributes:
* 1st attribute is the initialization and the 2nd attribute is the function curl_exec()
*
* the purpose of the 1st attribute is to initialize the code and the purpose of the 2nd
* attribute is to calculate and manipulate the 1st attribute.
*
* simple enough?
*
* now the call to curl_exec() executes the cURL engine.
*/
$result = curl_exec($curl);
// after that, we can close the cURL engine
curl_close($curl);
/**
* after the close of the cURL engine, it's time to
* get the content sent back by cURL engine.
*
* $result contains the response from the server.
*
* the response from the server contains a long string.
*
* so you would have to format how your content to be
* sent back to the client.
*
* this means that in your remote host script that does all
* of the responses to your client's requests would need to
* format the long string using delimiters, i.e., '|', '&', '#', etc.
*
* how you format your content to be sent back is up to you.
* and once you get the content, you can unravel/unformat your
* content accordingly.
*/
echo $result;
?>
As you can see, it is very easy to use cURL script to transfer data to and from the remote host.
Let's see a real example using cURL script to retrieve the content of a remote website: any content that appears on the remote website, it's a fair game, including a web site of singer Lady Gaga!
In this example, the content data of Lady Gaga's website is assigned to the variable $result. For example:
<?php
$curl = curl_init();
/**
* after all of initialization has been done, we can set
* all of the options needed inline.
*
* these options will connect our client to the remote host
*/
curl_setopt($curl, CURLOPT_URL, "https://www.ladygaga.com");
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_HEADER, false);
$result = curl_exec($curl);
// after that, we can close the cURL engine
curl_close($curl);
/**
* when we echo the value of the variable $result to
* the screen, we will see the picture/content of a web site
* of singer Lady Gaga.
*
* give it a try and see what happens!
*/
echo $result;
?>
cURL script is a very powerful tool for transfering data and receiving data back from the remote host. Please Google the term cURL to learn more using your favorite client-side languages of your choice.
Again, this is just a brief overview of the request/response model using cURL. For more check out the guides/tutorials mentioned earlier.
Now you have choices to transfer data using a request/response model. The above examples can be achieved using Ajax like shown in the following:
<script language="javascript" type="text/javascript">
/** this section part of the code is for browser initialization **/
/* Create a new XMLHttpRequest object to talk to the Web server */
var xmlHttp = false;
if (document.window.XMLHttpRequest)
{
//creating a non-MS browser object
xmlHttp = new XMLHttpRequest();
}
else if (document.window.ActiveXObject)
{
// this is the newer MS browser object and not even
// bother to test for older versions
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
}
else
{
document.write("unknown browser");
}
if (!xmlHttp)
{
alert("Error initializing XMLHttpRequest!");
}
/** this section part of the code is the response from the server **/
xmlhttp.onreadystatechange = function()
{
// object variable 'this' refers to an xmlHttpRequest object
// you could also just use the already initialized variable 'xmlhttp' object
if (this.readyState == 4 && this.status == 200)
{
var myObj = JSON.parse(this.responseText);
/**
* now variable myObj contains the decoded Javascript data object that looks
* like this:
*
* {"name" : "John Doe", "email" : "john@doe.com", "occupation" : "Programmer"}
*
* now that looks just like the encoded JSON data structure.
* yes, that is Javascript object.
*
* now you can access the decoded Javascript data object by referring to its
* object keys.
* for example: myObj.name, myObj.email, myObj.occupation, etc.
*
* below, assuming you have an HTML element that has an id attribute called "test",
* you can populate data like the following:
*/
document.getElementById("test").innerHTML = myObj.name;
}
};
/** this section part of the code is for pre-sending initialization **/
// right here, we are requesting server-side script: test.php
// notice also that we're using GET instead of POST
// we're not sending anything to the server -- we're only requesting from the server
// if you want to use POST instead of GET it is very easy to modify.
// see examples shown later and as well as examples in chapters 10 and 11
// of course, for the url, you need to specify a complete url path:
// http://www.example.com/local/directory/folder/test.php
xmlhttp.open("GET", "test.php", true);
/** this section part of the code is for the actual sending the request **/
// after that, we can just go ahead and send the request to the server
xmlhttp.send();
</script>
A very simple CURL script to send data to the server endpoint to charge the credit card.
<?php
// get the customer's credit card info from HTML form that the customer filled out in the form fields
$firstName = $_POST['firstname'];
$lastName = $_POST['lastname'];
$address = $_POST['address'];
$city = $_POST['city'];
$state = $_POST['state'];
$zip = $_POST['zip'];
$ccNumber = $_POST['ccNum'];
$month = $_POST['expiryMonth'];
$year = $_POST['expiryYear'];
$CVNnum = $_POST['CVNnumber'];
$amount = '129.95';
$nv_field = [
"customer_card_num" => $ccNumber,
"card_exp_month" => $month,
"card_exp_year" => $year,
"card_cvv" => $CVNNum,
"charge_amount" => $amount,
"customer_first_name" => $firstName,
"customer_last_name" => $lastName,
"customer_address" => $address,
"customer_city" => $city,
"customer_state" => $state,
"zip_code" => $zip,
];
$field = array();
foreach ($nv_field as $key => $value)
{
$field .= "$key=" . urlencode( $value ) . "&";
}
// CURLOPT_POST which turns HTTP POST on,
// and CURLOPT_POSTFIELDS which contains an array of our post data to submit.
// this array data can be used to submit data ($field) to the endpoint payment processor.
# this is the endpoint url to send this credit card info to get charged
$enpoint_payment_processor_url = "http://www.enpoint_payment_processor.com/payment/processor.php";
// you might find a more elegance way of preparing these credit card items for sending to
// the payment processor than it is shown in here!!!
// to start, open the url to connect to payment processor endpoint
$init = curl_init($enpoint_payment_processor_url);
/** setting some options **/
// set to 0 to eliminate header info from response
curl_setopt($init, CURLOPT_HEADER, 0);
// set it to true to turn the HTTP POST REQUEST protocol "ON"
curl_setopt($init, CURLOPT_POST, true);
// set CURLOPT_RETURNTRANSFER to true (or 1) to get CURL to send back the response
curl_setopt($init, CURLOPT_RETURNTRANSFER, true);
// use HTTP POST to send form data contains in $field
curl_setopt($init, CURLOPT_POSTFIELDS, $field); // http_build_query($field)
/** you can set some more options if you need to **/
// now execute post, and at this point, the server (endpoint) should be ready to response
$response = curl_exec($init);
// now we're done with the request and close the url endpoint connection
curl_close ($init);
// now you can parse the server (endpoint) response $response
// how you parse it depends on how you format your response in the server code.
// if your server response to you using json string then you need to parse it using
// json method: json_decode()
// if a server responses back using an array name/value pairs, then you need to parse it accordingly.
// if it is from the credit card payment processing companies, read their documentation.
// also, for credit card processing API, they probably require you to include some type of
// id, authentication, or reference, or account number to be sent to the endpoint so that they
// can identify who you are requesting their resources/services from their endpoint.
// as stated earlier, this is just a very simple and minimal code illustration.
// to do credit card processing request, you probably would need to set some more options and do
// some error handling as well.
?>
There you have it!!!
Make note: CURL is a very popular and powerful language/plugin tool to use in payment processing tasks (or API)!!!
Section 1.7: A touch of Financial Information eXchange (FIX) or FIXMLIn the previous sections you saw a request/response model using Ajax, jQuery, cURL; and in this section, we'll see how FIXML can be used as a request/response model to transfer data just like Ajax and jQuery.
Please note that this is just a brief overview of the request/response model using FIXML. For more, please check out the official website that contains everything about FIXML
The Financial Information eXchange ("FIX") Protocol is a series of messaging specifications for the electronic communication of trade-related messages, particularly, stocks and options trading. It has been developed through the collaboration of banks, broker-dealers, exchanges, industry utilities and associations, institutional investors, and information technology providers from around the world.
These market participants share a vision of a common, global language for the automated trading of financial instruments. In other words, you can use FIXML to transfer data to the server and the server will return the data you requested back to you (or more specifically, to your client application). It's a request/response transfer protocol for the financial industry.
To transfer data using FIXML or to fetch/retrieve data from the server using FIXML, you have to write a client script using client-side scripting languages such as Javascript, ASP, etc to push FIXML data format to the server and the server will response once it sees the FIXML data formatted request.
Let's see the FIXML data format to request to the server. As may have already guessed: FIXML is an electronic communication for the financial industry, particularly, stocks and options trading-related actions.
Let's see how to request a stock order to buy a stock (or options for that matter).
# Buy Order
<FIXML xmlns="http://www.fixprotocol.org/FIXML-5-0-SP2">
<Order TmInForce="0" Typ="1" Side="1" Acct="12345678">
<Instrmt SecTyp="CS" Sym="F"/>
<OrdQty Qty="1"/>
</Order>
</FIXML>
As you can see above, we placed a day order to buy 1 share of F (Ford Company) at market price on account 12345678. typ="1" means ???. Make note that the words typ and SecTyp. Those are not mis-typed -- they're the FIXML's real protocol keywords. I don't know about you -- I'm so annoyed about this spelling without the 'e'. I don't know what the reason is to omit the 'e'. But I'm so annoyed having to type without the 'e'.
# Buy to Cover (closing a short position)
<FIXML xmlns="http://www.fixprotocol.org/FIXML-5-0-SP2">
<Order TmInForce="0" Typ="2" Side="1" AcctTyp="5" Px="13" Acct="12345678">
<Instrmt SecTyp="CS" Sym="F"/>
<OrdQty Qty="1"/>
</Order>
</FIXML>
As you can see above, we placed a day order to buy to cover 1 share of F at $13 on account 12345678. typ="2" means ????
#
<FIXML xmlns="http://www.fixprotocol.org/FIXML-5-0-SP2">
<OrdCxlRplcReq TmInForce="0" Typ="2" Side="1" Px="15" Acct="12345678" OrigID="SVI-12345678">
<Instrmt SecTyp="CS" Sym="F"/>
<OrdQty Qty="1"/>
</OrdCxlRplcReq>
</FIXML>
To be continued!!!
#
To be continued!!!
#
As you can see, you have several options in requesting data from the server and getting the response from the server.
Section 1.8: Conclusion
Chapter 2
Section 2.1: Introduction
Most Web applications use a request/response model that gets an entire HTML page from the server. The result is a back-and-forth that usually involves clicking a button, waiting for the server, clicking another button, and then waiting some more. With Ajax and the XMLHttpRequest object, you can use a request/response model that never leaves users waiting for a server to respond. In this chapter, I will show you how to create XMLHttpRequest instances in a cross-browser way, construct and send requests, and respond to the server.
In the last chapter of this book, you were introduced to the Ajax applications and looked at some of the basic concepts that drive Ajax applications. At the center of this was a lot of technology that you probably already know about: JavaScript, HTML and XHTML, a bit of dynamic HTML, and even some DOM (the Document Object Model). In this chapter, I will zoom in from that 10,000-foot view and focus on specific Ajax details.
In this chapter, you'll begin with the most fundamental and basic of all Ajax-related objects and programming approaches: The XMLHttpRequest object. This object is really the only common thread across all Ajax applications and -- as you might expect -- you will want to understand it thoroughly to take your programming to the limits of what's possible. In fact, you'll find out that sometimes, to use XMLHttpRequest properly, you explicitly won't use XMLHttpRequest.
What in the world is that all about?
Section 2.2: Web 2.0 at a glance
First, take this last bit of overview before you dive into code -- make sure you're crystal clear on this idea of the Web 2.0. When you hear the term Web 2.0, you should first ask, "What's Web 1.0?" Although you'll rarely hear Web 1.0, it is meant to refer to the traditional Web where you have a very distinct request and response model. For example, go to Amazon.com and click a button or enter a search term. A request is made to a server and then a response comes back to your browser. That request has a lot more than just a list of books and titles, though; it's actually another complete HTML page. As a result, you probably get some flashing or flickering as your Web browser's screen is redrawn with this new HTML page. In fact, you can clearly see the request and response, delineated by each new page you see.
The Web 2.0 dispenses with this very visible back-and-forth (to a large degree). As an example, visit a site like Google Maps or Flickr. On Google Maps, for example, you can drag the map around and zoom in and zoom out with very little redrawing. Of course, requests and responses do go on here, but all behind the scenes. As a user, the experience is much more pleasant and feels a lot like a desktop application. This new feel and paradigm is what you see when someone refers to Web 2.0.
What you should care about then is how to make these new interactions possible. Obviously, you've still got to make requests and field responses, but it's the redrawing of the HTML for every request/response interaction that gives the perception of a slow, clunky Web interface. So clearly you need an approach that allows you to make requests and receive responses that include only the data you need, rather than an entire HTML page as well. The only time you want to get a whole new HTML page is when ... well ... when you want the user to see a new page.
But most interactions add details or change body text or overlay data on the existing pages. In all of these cases, Ajax and a Web 2.0 approach make it possible to send and receive data without updating an entire HTML page. And to any frequent Web surfer, this ability will make your application feel faster, more responsive, and bring them back over and over again.
Section 2.3: Introducing XMLHttpRequest
To make all this flash and wonder actually happen, you need to become intimately familiar with a JavaScript object called XMLHttpRequest. This little object -- which has actually been around in several browsers for quite a while -- is the key to Web 2.0, Ajax, and pretty much everything else you learn about in this book. To give you a really quick overview, these are just a few of the methods and properties you'll use on this object:
1. open(): Sets up a new request to a server.
2. send(): Sends a request to a server.
3. abort(): Bails out of the current request.
4. readyState: Provides the current HTML ready state.
5. responseText: The text that the server sends back to the client in response to a request.
Don't worry if you don't understand all of this (or any of this for that matter) -- you'll learn about each method and property in the next several chapters. What you should get out of this, though, is a good idea of what to do with XMLHttpRequest. Notice that each of these methods and properties relate to sending a request and dealing with a response. In fact, if you saw every method and property of XMLHttpRequest, they would all relate to that very simple request/response model. So clearly, you won't learn about an amazing new GUI object or some sort of super-secret approach to creating user interaction; you will work with simple requests and simple responses. It might not sound exciting, but careful use of this one object can totally change your applications.
The simplicity of new
First, you need to create a new variable and assign it to an instance of the XMLHttpRequest object. That's pretty simple in JavaScript; you just use the new keyword with the object name, like you see in Listing 1.
Listing 1. Create a new XMLHttpRequest object
<script language="javascript" type="text/javascript">
var request = new XMLHttpRequest();
</script>
|
Before I move on, I want to clarify this one nagging issue that seems to get a lot of people confused, and that is, the use of 'var' and 'let' keywords.
The var keyword signifies the variables being declared as global variables in a global scope; while on the other hand, let keyword signifies the variables being declared as local variables in a local block scope.
let allows you to declare variables that are limited in scope to (local) block or statement of expression: the opposite of var.
var is a keyword that allows you to define a variable globally in a global context regardless of block scope.
For example:
for() loop using let variable:
for (let i = 0; i < 10; i++)
{
// i is visible in a local block thus is logged in the console as 0, 1, 2,...., 9
console.log(i);
}
// throws an error as "i is not defined" because i is not visible outside for() loop
console.log(i);
for() loop using var variable:
for (var i = 0; i < 10; i++)
{
// i is visible in a local block thus is logged in the console as 0, 1, 2,...., 9
console.log(i);
}
// i is visible here too (outside) in a global scope. thus is logged as 10.
console.log(i);
|
Variables declared by let have their scope in the block for which they are defined, as well as in any contained sub-blocks. In this way, let works very much like var. The main difference is that the scope of a var variable is the entire enclosing function. For example:
letTest() function using let variable:
function letTest()
{
/**
* this is a local scope in a function.
*
* in a 'function' let works very much like var.
*
* remember the rule above:
*
* let have their scope
* in the block for which they are defined,
* as well as in any contained sub-blocks.
*
* the key phrase is: 'block for which they are defined'
*/
// declaring x as a local scope variable
let x = 1;
{
// this is a local scope sub-block
// declaring x as a local scope sub-block variable
let x = 2; // different variable - a local sub-block variable!
console.log(x); // 2
/**
* ok, let's comment out this: let x = 2 and see what happens!
* this inner console.log(x) above will still output a 1. why?
*
* pay special attention to these phrases:
*
* in the block for which they are defined,
* as well as in any contained sub-blocks.
*
* in this case, the latter phrase is more applicable, meaning it is
* visible in the current block as well as in the sub-block.
*
* ok, now consider this: comment out: let x = 1 and
* don't forget to uncomment: let x = 2 and see what happens!
*
* console.log(x) above will still output a 2 because it is in a local block.
*
* however, the console.log(x) below outside of this local block will output
* an "undefined". why?
*
* because console.log(x) is outside of the block in which x was defined,
* and therefore, not visible to the outer global block, which console.log(x)
* below is in.
*/
}
console.log(x); // 1
}
varTest() function using var variable:
function varTest()
{
// this is a global scope
// declaring x as a global scope variable
var x = 1;
{
// declaring x as a local scope variable but has a global scope as well.
// actually, x points to the same memory location as the one above!
var x = 2; // same variable but in a sub-block in the same memory location!
console.log(x); // 2
}
// as you can see in a global scope, all variables with the same name
// point to the same memory location, and thus assigning 2 to x
// places 2 to the same memory location occupied by x = 1
console.log(x); // 2
/**
* think of it this way:
*
* in a global scope, you have one memory location for each variable.
* for example, you declare a variable x and this x occupies one memory location.
* along the course of your programming you assign a value to this variable
* and that value stays there for a while.
*
* now somewhere in the blocks, whether in sub-blocks or what have you,
* you change that variable value to a different value, i.e., x = 10.
* now 10 is placed in the memory location previously occupied by an old value
* that you gave it to x; and therefore, wiping out that old value entirely.
*
* now this occurs only if you haven't declare the same x variable in that
* particular block. if you have, then that 10 is assigned to that local x variable;
* whereby leaving the x variable in the global scope uneffected by this assignment.
*
* this occurs only if you haven't declare the same x variable in that particular
* local block scope.
*/
}
|
So use let and var appropriately!
<script language="javascript" type="text/javascript">
var request = false;
try
{
request = new XMLHttpRequest();
}
catch (failed)
{
request = false;
}
if (!request)
{
alert("Error initializing XMLHttpRequest!");
}
</script>
|
<script language="javascript" type="text/javascript">
var request = false;
try
{
request = new XMLHttpRequest(); //creating object for non-Microsoft browsers
}
catch (trymicrosoft)
{
try
{
// creating object for Microsoft browser newer version: Msxml2
request = new ActiveXObject("Msxml2.XMLHTTP");
}
catch (othermicrosoft)
{
try
{
//creating object for Microsoft browser older version
request = new ActiveXObject("Microsoft.XMLHTTP");
}
catch (failed)
{
request = false;
}
} // end othermicrosoft
} // end trymicrosoft
if (!request)
{
alert("Error initializing XMLHttpRequest!");
}
</script>
|
As you can see, Microsoft has two versions of MSXML for whatever the reasons were: Msxml2 probably the enhanced version and Msxml probably the older version. Anyhow, this code tries to create the XMLHttpRequest object using one version of MSXML; if that fails, it then creates the XMLHttpRequest object using the other version. If neither of these work, the request variable is set to false, to tell your code that something hasn't worked. If that's the case, you've probably got a non-Microsoft browser and need to use different code to do the job.
It's easy to get lost in the curly braces, so I'll walk you through this one step at a time:Okay, all that talk about two versions of Microsoft browsers was for educational and informational purpose only, but in realitity, you don't need to write two conditions to test for both Microsoft browser versions as shown above.
A good programming practice is to write code as cleanly and effeiciently as possible without compromising quality or robustness. This means you can use a much cleaner version of the browser code illustrated above.
Here is a much cleaner and simpler browser code initialization that works even better than the version that just described above. As a matter of fact, nowaday no one in the right mind would still use the older versions of MS browsers.
Besides, today's operating systems would not even support such outdated older browser versions anyway, and that's why this simpler code below is very popular among programmers because Microsoft has enhanced older version called Microsoft.XMLHTTP to make it more robust and up to date.
In other words, the much older version Microsoft.XMLHTTP has been enhanced (including its class ActiveXObject) to make it more robust and up to date. It also dropped the other older version called Msxml2.XMLHTTP completely.
Now it is rallying around behind their newest enhanced version Microsoft.XMLHTTP and Microsoft will continue to update and enhance its flagship class ActiveXObject to the distance future as well.
Here is a much cleaner, simpler, and robust browser code:
<script language="javascript" type="text/javascript">
/* Create a new XMLHttpRequest object to talk to the Web server */
var xmlHttp = false;
if (document.window.XMLHttpRequest) // notice that the XMLHttpRequest without the "()"
{
//creating a non-MS browser object
xmlHttp = new XMLHttpRequest(); // notice that the XMLHttpRequest with the "()"
}
else if (document.window.ActiveXObject) // notice that the ActiveXObject without the "()"
{
// this is the newer MS browser object and not even
// bother to test for older versions
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); // notice that the ActiveXObject with the "()"
}
else
{
document.write("unknown browser");
}
if (!xmlHttp)
{
alert("Error initializing xmlHttp browser object!");
}
</script>
|
<script language="javascript" type="text/javascript">
/* Create a new XMLHttpRequest object to talk to the Web server */
/* Notice the use of the keyword 'var' to declare a global scope */
var request = false;
public function createRequest()
{
if (document.window.XMLHttpRequest)
{
//creating a non-MS browser object
request = new XMLHttpRequest();
}
else if (document.window.ActiveXObject)
{
// this is the newer MS browser object and not even
// bother to test for older versions
request = new ActiveXObject("Microsoft.XMLHTTP");
}
else
{
document.write("unknown browser");
}
if (!request)
{
alert("Error initializing XMLHttpRequest!");
}
} //end createRequest()
</script>
|
Or for the old outdated Microsoft browser code:
<script language="javascript" type="text/javascript">
/* Create a new XMLHttpRequest object to talk to the Web server */
/* Notice the use of the keyword 'var' to declare a global scope */
var request = false;
public function createRequest()
{
try
{
request = new XMLHttpRequest();
}
catch ()
{
// no need to output the error. we'll go directly to try:
try
{
// this is the newer MS browser object and not even
// bother to test for older versions
request = new Microsoft.XMLHTTP();
}
catch (err)
{
// you can print out the error using message property:
// err.message
// however, the test below does the job for us already!
request = false;
}
}
if (!request)
{
alert("Error initializing XMLHttpRequest!");
}
} //end createRequest()
</script>
|
<script language="javascript" type="text/javascript">
/* Create a new XMLHttpRequest object to talk to the Web server */
/* Notice the use of the keyword 'var' to declare a global scope */
var request = false;
public function createRequest()
{
if (document.window.XMLHttpRequest)
{
//creating a non-MS browser object
request = new XMLHttpRequest();
}
else if (document.window.ActiveXObject)
{
// this is the newer MS browser object and not even
// bother to test for older versions
request = new ActiveXObject("Microsoft.XMLHTTP");
}
else
{
document.write("unknown browser");
}
if (!request)
{
alert("Error initializing XMLHttpRequest!");
}
} //end createRequest()
public function getCustomerInfo()
{
request = createRequest();
// Right here where you do any Ajax work!
// For example, do something with the request variable
// See the following:
// Build the URL to connect to the server. See listing 8
let url = "/script/getZipCode.php?city=" + escape(city) +
"&state=" + escape(state);
// Open a connection to the server
request.open("GET", url, true);
// Setup a function for the server to run when it's done
request.onreadystatechange = updatePage;
// Send the request
request.send(null);
}
</script>
|
The only concern with this code -- and the reason most Ajax programmers don't use this approach -- is that it delays error notification, meaning that when a user enters data into the input box, Ajax engine doesn't fire off the response until the XMLHttpRequest object has been created, which in this case, getCustomerInfo() had to be called first and then the XMLHttpRequest object is created. Whereas in the static JavaScript code illustrated in the previous example above, the XMLHttpRequest object is created (and stored in the RAM) even before the user ever got to see the full page being completely displayed.
Suppose you have a complex form with 10 or 15 fields, selection boxes, and the like, and you fire off some Ajax code when the user enters text in field 14 (way down the form).
At that point, getCustomerInfo() runs, tries to create an XMLHttpRequest object, and fails. Then an alert is spit out to the user, telling them (in so many words) that they can't use this application. But the user has already spent time entering data in the form! That's pretty annoying and annoyance is not something that typically entices users back to your site.
In the case where you use static JavaScript, the user is going to get an error as soon as they hit your page. Is that also annoying? Perhaps; it could make users mad that your Web application won't run on their browser. However, it's certainly better than spitting out that same error after they've spent 10 minutes entering information.
For that reason alone, I encourage you to set up your code statically (using static JavaScript illustrated in the previous above) and your users know early on about possible problems.
Section 2.6: Sending requests with XMLHttpRequestIn order to send a request to the server, you need a URL to connect to. So the first thing you need to determine is to set or construct the URL of the server to connect to. This isn't specific to Ajax -- obviously you should know how to construct a URL by now -- but is still essential to making a connection.
In most applications, you'll construct this URL from some set of static data combined with data from the form your users work with. Static data is the data contained in the current script like in some variables, i.e., data contains in variable url. For example, Listing 7 shows some JavaScript that grabs the (non-static) value of the phone number field that the user enters in the input box of the form and then constructs a URL using that data.
Listing 7. Build a request URL
<script language="javascript" type="text/javascript">
/* Create a new XMLHttpRequest object to talk to the Web server */
var request = false;
if (document.window.XMLHttpRequest)
{
//creating a non-MS browser object
request = new XMLHttpRequest();
}
else if (document.window.ActiveXObject)
{
// this is the newer MS browser object and not even
// bother to test for older versions
request = new ActiveXObject("Microsoft.XMLHTTP");
}
else
{
document.write("unknown browser");
}
if (!request)
{
alert("Error initializing XMLHttpRequest!");
}
public function getCustomerInfo()
{
// grab the phone # from the input box the user enters in
// the form in Listing 8.
// phone contains a non-static data from the form
let phone = document.getElementById("phone").value;
// Do something with the request variable (or phone number) ....
// In this case, we'll set it up and prepare to send it to
// the server for processing
// url contains both static (the host) and non-static (phone)
let url = "http://www.example.com/cgi-local/lookupCustomer.php?phone=" +
escape(phone);
}
</script>
|
Here is the same code above but uses the old Microsoft browser version in case anyone is still using legacy code.
Listing 7a. Build a request URL
<script language="javascript" type="text/javascript">
/* Create a new XMLHttpRequest object to talk to the Web server */
var request = false;
try
{
request = new XMLHttpRequest();
}
catch ()
{
// no need to output the error. we'll go directly to try:
try
{
// this is the newer MS browser object and not even
// bother to test for older versions
request = new Microsoft.XMLHTTP();
}
catch (err)
{
// you can print out the error using message property:
// err.message
// however, the test below does the job for us already!
request = false;
}
}
if (!request)
{
alert("Error initializing XMLHttpRequest!");
}
public function getCustomerInfo()
{
// grab the phone # from the input box the user enters in
// the form in Listing 8.
// phone contains a non-static data from the form
let phone = document.getElementById("phone").value;
// Do something with the request variable (or phone number) ....
// In this case, we'll set it up and prepare to send it to
// the server for processing
// url contains both static (the host) and non-static (phone)
let url = "http://www.example.com/cgi-local/lookupCustomer.php?phone=" +
escape(phone);
}
</script>
|
<body>
<p>This is just an ordinary HTML form!</p>
<form action="POST">
<p>Enter your phone number:
<input type="text" size="14" name="phone" id="phone"
onChange()="getCustomerInfo();" />
</p>
<p>Your order will be delivered to:</p>
<div id="address">
<p>Type your order in here:</p>
<p><textarea name="order" rows="6" cols="50" id="order"></textarea></p>
<p><input type="submit" value="Order Pizza" id="submit" /></p>
</form>
</body
|
let url = "/cgi-local/lookupInfo.php?phone=" + escape(phone) + "&email=" + escape(email) + "&address=" + escape(address) + "&city=" + escape(city) + "&zipcode=" + escape(zipcode);
Please note that you need to use a complete url of the remote host you're trying to connect to, such as http://www.remotehostexample.com/. And as well as any folder/directory names followed by the script name. For example, http://www.remotehostexample.com/local_folder/scriptname.php. The example url's shown in this book omit the full and proper url details. Self-explanatory!
Section 2.7: Opening the requestinitialize() (or some other names) would have been appropriate since it initializes and prepare the URL to get it ready to be sent to the server.
function getCustomerInfo()
{
let phone = document.getElementById("phone").value;
let url = "/cgi-local/lookupCustomer.php?phone=" + escape(phone);
request.open("GET", url, true);
}
|
<script language="javascript" type="text/javascript">
/* Create a new XMLHttpRequest object to talk to the Web server */
var request = false;
if (document.window.XMLHttpRequest)
{
//creating a non-MS browser object
request = new XMLHttpRequest();
}
else if (document.window.ActiveXObject)
{
// this is the newer MS browser object and not even
// bother to test for older versions
request = new ActiveXObject("Microsoft.XMLHTTP");
}
else
{
document.write("unknown browser");
}
if (!request)
{
alert("Error initializing XMLHttpRequest!");
}
/* declare and initialize some object variables */
//I add this line to make it more interesting
let name = document.getElementById("name").value;
//I add this line to make it more interesting
let address = document.getElementById("address").value;
let phone = document.getElementById("phone").value;
//I add this line to make it more interesting
let order = document.getElementById("order").value;
// right here where it waits for the server to response.
// when the server responses it sets this "onreadystatechange" property with codes.
request.onreadystatechange = function()
{
// object variable 'this' refers to an xmlHttpRequest object
// you could also just use the already initialized variable 'request' object
if (this.readyState == 4 && this.status == 200)
{
/**
* at this point, the server has finished sending back its response.
* now we can get that response in the property variable responseText.
*/
response = JSON.parse(this.responseText);
/**
* now we can use the data contains in variable response in the form
* of a Javascript array object that parse() parses it into a
* Javascript array object.
*
* the server-side script just sent a response to this client by just
* sending back name, address, phone, order.
* you might want to response to the client with a more meaningful response
* than just sending back name, address, phone, order.
*/
name = response.name;
document.write(name + "<br>");
address = response.address;
document.write(address + "<br>");
phone = response.phone;
document.write(phone + "<br>");
order = response.order;
document.write(order + "<br>");
}
/* now we need to prepare the url and do some initilization */
/**
* notice that the URL has the current time appended to it.
* That ensures that the request isn't cached after it's sent
* the first time but is recreated and resent each time this
* method is called; the URL will be subtly different because of
* the changing time stamp.
*
* This is a common trick to ensure that POSTing to a script actually
* repeatedly generates a new request each time, and the Web browser
* doesn't try and cache responses from the server.
*
* so don't forget to use this neat trick when send through POST.
*
* notice also that the name/value pairs are not appended to the url like GET.
*
* instead it will be sent as the argument of send()
*/
let url = "/cgi-local/lookupCustomer.php?timeStamp=" + new Date().getTime();
// we need to prepare the header properly before sending a POST
request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
request.open("POST", url, true); //<--- here is the POST request
// Below: notice the use of send() and appending all name/value pair
// variables as one long string
// this sends the long string to a server-side script named:
// lookupCustomer.php
request.send("name=" + escape(name) + "&address=" + escape(address) +
"&phone=" + escape(phone) + "&order=" + escape(order));
}
</script>
|
<script language="javascript" type="text/javascript">
/* Create a new XMLHttpRequest object to talk to the Web server */
var request = false;
if (document.window.XMLHttpRequest)
{
//creating a non-MS browser object
request = new XMLHttpRequest();
}
else if (document.window.ActiveXObject)
{
// this is the newer MS browser object and not even
// bother to test for older versions
request = new ActiveXObject("Microsoft.XMLHTTP");
}
else
{
document.write("unknown browser");
}
if (!request)
{
alert("Error initializing XMLHttpRequest!");
}
/* declare and initialize some object variables */
//I add this line to make it more interesting
let name = document.getElementById("name").value;
//I add this line to make it more interesting
let address = document.getElementById("address").value;
let phone = document.getElementById("phone").value;
//I add this line to make it more interesting
let order = document.getElementById("order").value;
// concatenate the name/value pairs and assign a variable (post_string) to it
let post_string = escape(name) + "&" + escape(address) +
"&" + escape(phone) + "&" + escape(order);
// concatenate the name/value pairs and assign a variable (post_string) to it
// you can do like this as well:
// let post_string = "name=" + escape(name) + "&address=" + escape(address) +
// "&phone=" + escape(phone) + "&order=" + escape(order);
/* now we need to prepare the url and do some initilization */
/**
* notice that the URL has the current time appended to it.
* That ensures that the request isn't cached after it's sent
* the first time but is recreated and resent each time this
* method is called; the URL will be subtly different because of
* the changing time stamp.
*
* This is a common trick to ensure that POSTing to a script actually
* repeatedly generates a new request each time, and the Web browser
* doesn't try and cache responses from the server.
*
* so don't forget to use this neat trick when send through POST.
*
* notice also that the name/value pairs are not appended to the url like GET.
*
* instead it will be sent as the argument of send()
*/
let url = "/cgi-local/lookupCustomer.php?timeStamp=" + new Date().getTime();
// we need to prepare the header properly before sending a POST
request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
request.open("POST", url, true); //<--- here is the POST request
// we can just send the request to the server. notice that instead of 'null', we are
// posting the long string to the server with a key/value pair, with key is the key.
request.send("key=" + post_string); // notice the key/value pair "key="post_string
// you can do like this as well:
// request.send(post_string); // POST the name/value pairs to server
// right here where it waits for the server to response.
// when the server responses it sets this "onreadystatechange" property with codes.
request.onreadystatechange = function()
{
// object variable 'this' refers to an xmlHttpRequest object
// you could also just use the already initialized variable 'request' object
if (this.readyState == 4 && this.status == 200)
{
/**
* at this point, the server has finished sending back its response.
* now we can get that response in the property variable responseText.
*/
response = JSON.parse(this.responseText);
/**
* now we can use the data contains in variable response in the form
* of a Javascript array object that parse() parses it into a
* Javascript array object.
*
* the server-side script just sent a response to this client by just
* sending back name, address, phone, order.
* you might want to response to the client with a more meaningful response
* than just sending back name, address, phone, order.
*/
name = response.name;
document.write(name + "<br>");
address = response.address;
document.write(address + "<br>");
phone = response.phone;
document.write(phone + "<br>");
order = response.order;
document.write(order + "<br>");
}
}
</script>
now in the server-side PHP script called lookupCustomer.php, you can response
to the client. for the first version, you can response to the client using code
similar to the following server-side PHP code. self-explantory!
<?php
// but first, we can grab the data sent by the client using $_POST
// if (isset($_POST["name"]))
// {
// $name = $_POST["name"];
// }
// if (isset($_POST["address"]))
// {
// $address = $_POST["address"];
// }
// if (isset($_POST["phone"]))
// {
// $phone = $_POST["phone"];
// }
// if (isset($_POST["order"]))
// {
// $order = $_POST["order"];
// }
// now retrieve an HTTP request using $_POST containing a key/value
if (isset($_POST["key"]))
{
$string = $_POST["key"];
}
else
{
exit();
}
// at this point we got the message/request from the client
// from here and onward, we will need to response to the client.
// see a brute force response in a little bit
// now $string contains this data: "name=John Doe&address=123 main st&phone=6123& ..."
// of course, while sending this long string, the browser will replace any space with
// these characters: %20, for example, John%20Doe&address123%20& .....
// now you have a POST data and you can do whatever you want, such as storing it in
// db and as well as responding to the client.
$data = exlode("&", $string);
// now $data contains an array data: [
// "name" => "John Doe", "address" => "123 main st",
// "phone" => "6123334444", "order" => "...."
// ]
// then tell the client we're sending a name/value pair JSON text data format
header("Content-Type: application/json; charset=UTF-8");
// right here where we will brute force sending a response to the client.
// but before sending it to the client, we need to format the array object $data and
// send it to the client as a JSON data format.
// see chapter 10 and 11 for more on JSON.
// sending name, address, phone, order to the client?
// well, you can find a more useful data to send to the client than this.
echo json_encode($data);
/* after responding to the client, store data in the database */
try
{
// of course, you need to provide proper connection parameters such as
// $hostingServer, $databaseName, $username, $password
$conn = new PDO("mysql:host=$hostingServer;dbname=$databaseName",
$username, $password);
}
catch (PDOException $e)
{
echo 'ERROR: Cannot connect to the server: ' . $e->getMessage();
}
try
{
$stmt = $conn->prepare("INSERT INTO customer (name, address, phone)
VALUES (?, ?, ?) ");
/**
* $data contains four items: name, address, phone, order.
* but the table only contains three fields, so execute() method only
* inserts the first three items into the first three fields in the table,
* leaving the extra item: order unused.
*
* if your code doesn't seem to show any data inserted in the table is because
* of this discrepancy of the data and the field table.
*
* if that is the case, you might need to format your $data to contain the
* same number of items as the number of the table fields.
*/
$stmt->execute($data);
}
catch (PDOException $e)
{
echo 'ERROR: Cannot insert data into the database: ' . $e->getMessage();
}
?>
|
Here is an old code, which was written sometime in 2004-5, using PHP's outdated mysql_ database engine. For an up-to-date code, see the previous PDO database engine example; or you can find some more PDO database engine examples later on, particularly in chapter 11.
In this example, I'm going to use PHP to handle the request and here is the example server-side script named:lookupCustomer.php.
<?php
//handling a request from the client script
if isset($_POST['name'])
$name = $_POST['name'];
if isset($_POST['address'])
$address = $_POST['address'];
if isset($_POST['phone'])
$phone = $_POST['phone'];
if isset($_POST['order'])
$order = $_POST['order'];
//now that we got all the info sent by the client, we can look up the customer's phone #
//Making connection to MySQL database server
$Conn = mysql_connect($localhost, $username, $password);
if (!$Conn)
{
die('Could not connect: ' . mysql_error());
}
@mysql_select_db($database) or die( "Unable to select database");
// Get customer's phone number from the database
$select = 'SELECT Phone, Name, Address;
$from = ' FROM Customer_Table';
$where = " `Phone` = '$phone' ";
$query = @mysql_query($select . $from . $where) or mysql_error();
if (mysql_num_rows($query) == 0)
{
echo ("Oop!! we have a new customer ... no phone # on our record.');
//so grab customer's info from the client form obtained earlier and .....
//save it in your database
$query = "INSERT INTO `Customer_Table`
(
`Name`, `Address`, `Phone`, `Order`
)
VALUES
(
'$name', '$address', '$phone', '$order'
)";
mysql_query($query) or mysql_error();
//Send customer data back to the client
//Let the client know we're sending back plain text data (not XML)
header("Content-Type: text/plain");
echo $name . '|' . $address . '|' . $phone . '|' . $order;
}
else
{
//Yeah!! we have a repeat customer ... welcome back!
//Let the client know we're sending back plain text data (not XML)
header("Content-Type: text/plain");
while ($row = mysql_fetch_array(query))
{
//Pick out data from resultset
$name = $row['Name'];
$address = $row['Address'];
$phone = $row['Phone'];
$order = $row['Order'];
//Send customer data back to the client
echo $name . '|' . $address . '|' . $phone . '|' . $order;
}//end while
}//end else
mysql_close($conn);
?>
|
function getCustomerInfo()
{
let phone = document.getElementById("phone").value;
let url = "/cgi-local/lookupCustomer.php?phone=" + escape(phone);
request.open("GET", url, true);
request.send(null);
}
|
Typically when you need to send something to the server or requesting something from the server [as is usually the case], you need to know server-side programming to perform some sort of tasks in response to the client's request. Server-side programming involves server-side scripts like PHP, Perl, Python, ASP, Ruby on the Rail, etc. These programming languages are suitable for performing tasks on the server.
Here is an old code, which was written sometime in 2004-5, using PHP's outdated mysql_ database engine. For an up-to-date code, see the previous PDO database engine example; or you can find some more PDO database engine examples later on, particularly in chapter 11.
In this example, we use PHP server-side programming language to look up customer's phone number (lookupCustomer.php) stored in the database. The lookupCustomer.php script looks like the following:
<?php
/***********************************
* Script to retrieve customer data *
* File: lookupCustomer.php *
************************************/
//You need to replace these values for your own db connection
$database="dbo99770110";
$localhost="dbserv.example.com";
$username="myUser123";
$password="dbPass123";
//Making connection to MySQL database server
$Conn = mysql_connect($localhost, $username, $password);
if (!$Conn)
{
die('Could not connect: ' . mysql_error());
}
@mysql_select_db($database) or die( "Unable to select database");
//Remember that you sent the request via a GET array:
//(request.open("GET", url, true);)
//So we'll use $_GET to grab the phone number from the client
//you could also grab customer's order ....
$Phone = $_GET['phone'];
// Get customer's phone number from the database
$select = 'SELECT Phone, Name, Address, City, State, Zipcode;
$from = ' FROM Customer_Table';
$where = " `Phone` = '$Phone' ";
$query = @mysql_query($select . $from . $where) or mysql_error();
if (mysql_num_rows($query) == 0)
{
echo ("Oop!! we have a new customer ... no phone # on our record.');
//so grab address from the client form instead .....
$Address = $_GET['address'];
$City = $_GET['city'];
$State = $_GET['state'];
$Zipcode = $_GET['zipcode'];
//Right here you might want to save customer data in your database
//Send customer data back to the client
//Let the client know we're sending back plain text data (not XML)
header("Content-Type: text/plain");
echo $Name . '|' . $Address . '|' . $City . '|' . $State . '|' .
$State . '|' . $Phone;
}
else
{
//Yeah!! we have a repeat customer ... welcome back!
//Let the client know we're sending back plain text data (not XML)
header("Content-Type: text/plain");
while ($row = mysql_fetch_array(query))
{
//Pick out data from resultset
$Name = $row['Name'];
$Address = $row['Address'];
$City = $row['City'];
$State = $row['State'];
$Zipcode = $row['Zipcode'];
$Phone = $row['Phone'];
//Send customer data back to the client
echo $Name . '|' . $Address . '|' . $City . '|' . $State . '|' .
$State . '|' . $Phone;
}//end while
}//end else
mysql_close($conn);
?>
|
$Sausage = $_GET['sausage'];
$Pepperoni = $_GET['pepperoni'];
$Olive = $_GET['olive'];
//and then echo out
echo $Sausage . $Pepperoni . $Olive;
|
I know I love pizza and I order pizza online on a regular basis. So I see some similarity in the way the request/response are interconnected.
Note: if you're working with PHP script, be careful with POST and GET arrays. If your customer fill in the order form and click the "Submit Order" on your website, that's is a POST request and you should use $_POST['sausage'] variable, unless your client script (JavaScript) grabs that item and sends it via a GET array instead. So be careful when working with PHP script.
function getCustomerInfo()
{
let phone = document.getElementById("phone").value;
let url = "/cgi-local/lookupCustomer.php?phone=" + escape(phone);
request.onreadystatechange = updatePage;
request.send(null);
}
|
<script language="javascript" type="text/javascript">
/* Create a new XMLHttpRequest object to talk to the Web server */
var request = false;
if (document.window.XMLHttpRequest)
{
//creating a non-MS browser object
request = new XMLHttpRequest();
}
else if (document.window.ActiveXObject)
{
// this is the newer MS browser object and not even
// bother to test for older versions
request = new ActiveXObject("Microsoft.XMLHTTP");
}
else
{
document.write("unknown browser");
}
if (!request)
{
alert("Error initializing XMLHttpRequest!");
}
public function getCustomerInfo()
{
// grab the phone # from the input box the user enters in
// the form in Listing 8.
let phone = document.getElementById("phone").value;
let url = "http://www.example.com/cgi-local/lookupCustomer.php?phone=" +
escape(phone);
request.open("GET", url, true);
request.onreadystatechange = updatePage;
request.send(null);
}
function updatePage()
{
alert("Server is done!");
}
</script>
|
This just spits out a handy alert, to tell you when the server is done. Of course, inside updatePage() you need to do/handle any Ajax response task accordingly instead of spitting out the message. However, there is some thing wrong with the way the code is setup as it stands right now.
Try this code in your own page, save the page, and then pull it up in a browser (if you want to see the XHTML at work from this example, refer back to Listing 8). When you enter in a phone number and leave the field, you should see the alert pops up; but click OK and it pops up again ... and again.
Depending on your browser, you'll get two, three, or even four alerts before the form stops popping up alerts. So what's going on? It turns out that you haven't taken into account the HTTP ready state, an important component of the request/response cycle.
Section 2.11: HTTP ready states
Earlier, I said that the server, once finished with a request, looks up what method to call in the onreadystatechange property of XMLHttpRequest. That's true, but it's not the whole truth. In fact, it calls that method every time the HTTP ready state changes. So what does that mean? Well, you've got to understand HTTP ready states first.
An HTTP ready state indicates the state or status of a request. It's used to figure out if a request has been started, if it's being answered, or if the request/response model has completed. It's also helpful in determining whether it's safe to read whatever response text or data that a server might have supplied. You need to know about five ready states in your Ajax applications:
0: The request is uninitialized (before you've called open()).
1: The request is set up, but hasn't been sent (before you've called send()).
2: The request was sent and is being processed (you can usually get content headers from the response at this point).
3: The request is being processed; often some partial data is available from the response, but the server hasn't finished with its response.
4: The response is complete; you can get the server's response and use it.
As with almost all cross-browser issues, these ready states are used somewhat inconsistently. You might expect to always see the ready state move from 0 to 1 to 2 to 3 to 4, but in practice, that's rarely the case. Some browsers never report 0 or 1 and jump straight to 2, then 3, and then 4. Other browsers report all states. Still others will report ready state 1 multiple times. As you saw in the last section, the server called updatePage() several times and each invocation resulted in an alert box popping up -- probably not what you intended!
For Ajax programming, the only state you need to deal with directly is ready state 4, indicating that a server's response is complete and it's safe to check the response data and use it. To account for this, the first line in your callback method should be as shown in Listing 13.
Listing 13. Check the ready state
function updatePage()
{
if (request.readyState == 4)
{
alert("Server is done!");
}
}
|
function updatePage()
{
if (request.readyState == 4)
{
if (request.status == 200)
{
alert("Server is done!");
}
}
}
|
function updatePage()
{
if (request.readyState == 4)
{
if (request.status == 200)
{
alert("Server is done!");
}
else if (request.status == 404)
{
alert("Url does not exist!");
}
else
{
alert("Error: status code is " + request.status);
}
}
}
|
This allows the server to set this text to virtually anything. In other words, it's up to the server-side script to set up the data format to send to client script. For instance, one script might return comma-separated values, another pipe-separated values (the pipe is the | character), and another may return one long string of text.
So it's all up to the server to format data and response. In other words, it's up to you to write your server-side script "how" to send back the request to the client script.
So because of the freedom we're allow to do, it is much easier to send data to client using JSON data structure. See chapter 10 and 11 for more.
Using JSON data structure is the most popular way for sending data from the server to the client. It is very easy to format and send, and as well as very easy to parse it on the client's end.
In the case of the example used in this section, the server returns a customer's last order and then their address, separated by the pipe symbol. The order and address are both then used to set values of elements on the form. Listing 16 shows the code that updates the display.
function updatePage()
{
if (request.readyState == 4)
{
if (request.status == 200)
{
let response = request.responseText.split("|");
document.getElementById("order").value = response[0];
document.getElementById("address").innerHTML =
response[1].replace(/\n/g, "");
}
else
{
alert("status is " + request.status);
}
}
}
|
As mentioned above, using JSON data structure is the most popular way for sending data from the server to the client. It is very easy to format and send, and as well as very easy to parse it on the client's end. The preceding illustration that shows how to parse data using the symbol pipe "|" was for educational purpose only; however, for practical purpose, I suggest that you use JSON data structure instead.
Section 2.13: Conclusion.Chapter 3
Section 3.1: Introduction
For many Web developers, making simple requests and receiving simple responses is all they'll ever need, but for developers who want to master Ajax, a complete understanding of HTTP status codes, ready states, and the XMLHttpRequest object is required. In this chapter, I will show you the different status codes and demonstrate how browsers handle each and he will showcase the lesser-used HTTP requests that you can make with Ajax.
In the last chapter in this book, I provided a solid introduction to the XMLHttpRequest object, the centerpiece of an Ajax application that handles requests to a server-side application or script, and also deals with return data from that server-side component. Every Ajax application uses the XMLHttpRequest object, so you'll want to be intimately familiar with it to make your Ajax applications perform and perform well.
In this chapter, I move beyond the basics in the last chapter and concentrate on more detail about three key parts of this request object:
1. The HTTP ready state
2. The HTTP status code
3. The types of requests that you can make
Each of these is generally considered part of the plumbing of a request; as a result, little detail is recorded about these subjects. However, you will need to be fluent in ready states, status codes, and requests if you want to do more than just dabble in Ajax programming. When something goes wrong in your application -- and things always go wrong -- understanding ready states, how to make a HEAD request, or what a 400 status code means can make the difference between five minutes of debugging and five hours of frustration and confusion.
XMLHttpRequest or XMLHttp: A rose by any other name Microsoft and Internet Explorer use an object called XMLHttp instead of the XMLHttpRequest object used by Mozilla, Opera, Safari, and most non-Microsoft browsers. For the sake of simplicity, I refer to both of these object types simply as XMLHttpRequest. This matches the common practice you'll find all over the Web and is also in line with Microsoft's intentions of using XMLHttpRequest as the name of their request object in Internet Explorer 7.0. (For more on this, look at Chapter 2 again.)
I'll look at HTTP ready states first.
Section 3.2: Digging deeper into HTTP ready states
You should remember from the last chapter that the XMLHttpRequest object has a property called readyState. This property ensures that a server has completed a request and typically, a callback function uses the data from the server to update a Web form or page. Listing 1 shows a simple example of this.
Listing 1. Deal with a server's response in a callback function
function updatePage()
{
if (request.readyState == 4)
{
if (request.status == 200)
{
let response = request.responseText.split("|");
document.getElementById("order").value = response[0];
document.getElementById("address").innerHTML =
response[1].replace(/\n/g, "");
}
else
{
alert("status is " + request.status);
}
}
}
|
readyState == 0), represents an uninitialized request. As soon as you call open() on your request object, this property is set to 1. Because you almost always call open() as soon as you initialize your request, it's rare to see readyState == 0. Furthermore, the uninitialized ready state is pretty useless in practical applications.
function getSalesData()
{
// Create a request object
createRequest();
alert("Ready state is: " + request.readyState);
// Setup (initialize) the request
let url = "/boards/servlet/UpdateBoardSales";
request.open("GET", url, true);
request.onreadystatechange = updatePage;
request.send(null);
}
|
function updatePage()
{
// Output the current ready state
alert("updatePage() called with ready state of " + request.readyState);
}
|
function updatePage()
{
if (request.readyState == 4)
{
let newTotal = request.responseText;
let totalSoldEl = document.getElementById("total-sold");
let netProfitEl = document.getElementById("net-profit");
replaceText(totalSoldEl, newTotal);
/* Figure out the new net profit */
let boardCostEl = document.getElementById("board-cost");
let boardCost = getText(boardCostEl);
let manCostEl = document.getElementById("man-cost");
let manCost = getText(manCostEl);
let profitPerBoard = boardCost - manCost;
let netProfit = profitPerBoard * newTotal;
/* Update the net profit on the sales form */
netProfit = Math.round(netProfit * 100) / 100;
replaceText(netProfitEl, netProfit);
}
}
|
function updatePage()
{
// Output the current ready state
alert("updatePage() called with ready state of " + request.readyState +
" and a response text of '" + request.responseText + "'");
}
|
function updatePage()
{
if (request.readyState == 4)
{
let response = request.responseText.split("|");
document.getElementById("order").value = response[0];
document.getElementById("address").innerHTML =
response[1].replace(/\n/g, "<br />");
}
}
|
function updatePage()
{
if (request.readyState == 4)
{
if (request.status == 200)
{
let response = request.responseText.split("|");
document.getElementById("order").value = response[0];
document.getElementById("address").innerHTML =
response[1].replace(/\n/g, "<br />");
}
else
alert("status is " + request.status);
}
}
|
function updatePage()
{
if (request.readyState == 4)
{
if (request.status == 200)
{
let response = request.responseText.split("|");
document.getElementById("order").value = response[0];
document.getElementById("address").innerHTML =
response[1].replace(/\n/g, "<br />");
}
else if (request.status == 404)
{
alert("Requested URL is not found.");
}
else if (request.status == 403)
{
alert("Access denied.");
}
else
{
alert("status is " + request.status);
}
}
}
|
function getSalesData()
{
// Create a request object
createRequest();
// Setup (initialize) the request
let url = "/boards/servlet/UpdateBoardSales";
request.open("HEAD", url, true);
request.onreadystatechange = updatePage;
request.send(null);
}
|
function updatePage()
{
if (request.readyState == 4)
{
alert(request.getAllResponseHeaders());
}
}
|
function updatePage()
{
if (request.readyState == 4)
{
if (request.status == 200)
{
alert("URL exists");
}
else if (request.status == 404)
{
alert("URL does not exist.");
}
else
{
alert("Status is: " + request.status);
}
}
}
|
For the description of the family of codes, see this link.
<?php
// Create a cURL handle
$ch = curl_init('http://www.example.com/');
// Execute
curl_exec($ch);
// Check HTTP status code
if (!curl_errno($ch))
{
switch ($http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE))
{
case 200: # OK -- meaning, the request was successfully and the response was also successfully
// do something, such as processing the response returned by the server
break;
case 201: # Created
// do something
break;
case 202: # Accepted
// do something
break;
case 203: # Non-Authoritative Information
// do something
break;
case 204: # No Content
// do something
break;
default:
echo 'Unexpected HTTP code: ', $http_code, "\n";
}
}
// Close handle
curl_close($ch);
?>
Continuing on to add some more settings.
<?php
// create cURL handle (ch)
$ch = curl_init();
if (!$ch)
{
die("Couldn't initialize a cURL handle");
}
// set some cURL options
// these settings are very minimal -- you can add more settings to suite your goal!
curl_setopt($ch, CURLOPT_URL, "http://www.example.com");
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 0);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
// execute
$response = curl_exec($ch);
if (empty($response))
{
// some kind of an error happened
die(curl_error($ch));
// close cURL handler
curl_close($ch);
}
else
{
$info = curl_getinfo($ch);
// close cURL handler
curl_close($ch);
if (empty($info['http_code']))
{
die("No HTTP code was returned");
}
else
{
// pick out the HTTP codes from the server response
switch ($http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE))
{
case 200: # OK -- meaning, the request was successfully and the response was also successfully
// do something, such as processing the response returned by the server
break;
case 201: # Created -- actually most of the time you don't even need to branch out to these
# codes -- maybe only certain situations only!
// do something
break;
case 202: # Accepted -- implement this if your situation needed
// do something
break;
case 203: # Non-Authoritative Information -- implement this if your situation needed
// do something
break;
case 204: # No Content -- implement this if your situation needed
// do something
break;
default:
echo 'Unexpected HTTP code: ', $http_code, "\n";
}
// echo results
echo "The server responded:
";
echo $http_code['http_code'];
}
}
?>
/**
* Here is a list of the Hypertext Transfer Protocol (HTTP) Status Code Registry
*
* As stated earlier, these codes are not specific to just Ajax, but rather,
* they are bourned out of the Web since the birth of the Web.
*/
HTTP Status Codes
Value Description
----- -----------
the 100 family: Connection
100 Continue
101 Switching Protocols
102 Processing
103 Early Hints
104-199 Unassigned (these codes are for user-defined code -- it's an all-purpose type of codes)
the 200 family: Successful 2xx
200 OK (the request went through ok and also the response came back ok)
201 Created -- if the request to create something is successful -- it's created successfully
202 Accepted -- it's accepted the sent content successfully
203 Non-Authoritative Information
204 No Content
205 Reset Content
206 Partial Content
207 Multi-Status
208 Already Reported
209-225 Unassigned (these codes are for user-defined code --it's an all-purpose type of codes)
226 IM Used
227-299 Unassigned (these codes are for user-defined code -- it's an all-purpose type of codes)
the 300 family: Redirection 3xx
300 Multiple Choices
301 Moved Permanently
302 Found
303 See Other
304 Not Modified
305 Use Proxy
306 (Unused)
307 Temporary Redirect
308 Permanent Redirect
309-399 Unassigned (these codes are for user-defined code -- it's an all-purpose type of codes)
the 400 family: Client Error 4xx
400 Bad Request
401 Unauthorized
402 Payment Required
403 Forbidden
404 Not Found
405 Method Not Allowed
406 Not Acceptable
407 Proxy Authentication Required
408 Request Timeout
409 Conflict
410 Gone
411 Length Required
412 Precondition Failed
413 Content Too Large
414 URI Too Long
415 Unsupported Media Type
416 Range Not Satisfiable
417 Expectation Failed
418 (Unused)
419-420 Unassigned (these codes are for user-defined code -- it's an all-purpose type of codes)
421 Misdirected Request
422 Unprocessable Content
423 Locked
424 Failed Dependency
425 Too Early
426 Upgrade Required
427 Unassigned
428 Precondition Required
429 Too Many Requests
430 Unassigned (these codes are for user-defined code -- it's an all-purpose type of codes)
431 Request Header Fields Too Large
432-450 Unassigned (these codes are for user-defined code -- it's an all-purpose type of codes)
451 Unavailable For Legal Reasons
452-499 Unassigned (these codes are for user-defined code -- it's an all-purpose type of codes)
the 500 family: Server Error 5xx
500 Internal Server Error
501 Not Implemented
502 Bad Gateway
503 Service Unavailable
504 Gateway Timeout
505 HTTP Version Not Supported
506 Variant Also Negotiates
507 Insufficient Storage
508 Loop Detected
509 Unassigned (these codes are for user-defined code -- it's an all-purpose type of codes)
510 Not Extended
511 Network Authentication Required
512-599 Unassigned (these codes are for user-defined code -- it's an all-purpose type of codes)
Chapter 4
Section 4.1: Introduction
Before I dive into the DOM, I want to explain one nagging issue that seems to confuse a lot of programmers, and that is, the difference between a class and an object.
Both class and object have the same meaning and both achieve the same purpose but differ only in the way they're implemented and used.
A class consists of constant variables, properties, and methods. Those are the three basic attributes of a class. That's all a class is: it has three attributes -- a very simple concept and yet very powerful.
Consider the following class definition:
<?php
class MyClass
{
// 1st attribute of the class (MyClass):
// declaring class constant variables
// COMMAND_EVENT_START, COMMAND_BEFORE_START,
// COMMAND_AFTER_START are constant variables
// command_start, before_start, after_start are constant values
const COMMAND_BEFORE_START = 'before_start';
const COMMAND_EVENT_START = 'command_start';
const COMMAND_AFTER_START = 'after_start';
// 2nd attribute of the class (MyClass):
class properties: properties must be declared prefacing with visibility control
public, protected, private are visibility control:
public make = 'Toyota';
protected model = 'Tundra';
private color = 'grey';
// 3rd attribute of the class (MyClass):
class methods: methods must be declared prefacing with visibility control
public, protected, private are visibility control:
public function test1()
{
// will output: An object is just a copy of the class.
document.write ("An object is just a copy of the class.");
}
public function test2(str)
{
// will output whatever string got passed in via str
document.write (str);
}
}
?>
And then consider this object creation:
str = 'An object is just a copy of the class.';
creating an instance of MyClass()
obj is an instance of the class MyClass. it is a copy or a clone of MyClass.
obj = new MyClass();
obj->test1(str);
will output an error message saying argument str is undefined in test1().
obj->test1();
will output ----> An object is just a copy of the class.
obj->test2();
will output an error message saying test2() requires at least one argument.
obj->test2(str);
will output -----> An object is just a copy of the class.
A class is the program you write (i.e., the MyClass class implementation above); while object (i.e., obj) is the copy of the class or the clone of the class, most often being known as the instance of the class.
A class resides in ROM (permanent memory area) whereas object (i.e., obj) resides in RAM (temporary memory area.)
In ROM, data is stored there permanently even when the computer is turned off. In a RAM memory area, on the other hand, data get stored temporarily while the program is running or while the computer is still turned on. When the computer is turned off, the RAM data (i.e., obj) is completely erased and is no longer stored in the RAM.
Instances of a class can be useful only while the program is running or while the computer is turned on; and when the program is not running or when the computer is turned off, instances of a class are no longer useful to a program; and therefore, it is stored in a temporary memory area.
Instances of a class can be created 'on the fly' at any time when needed by a program [as you can see above: obj = new MyClass()].
Instances of a class are often being created from everywhere when needed (i.e., libraries, frameworks, and other classes, etc.)
So there is no need to store instances of a class permanently in permanent memory spaces and wasting valuable memory spaces.
The great divide between programmers (who work with back-end applications) and Web programmers (who spend their time writing HTML, CSS, and JavaScript) is long standing. However, the Document Object Model (DOM) bridges the chasm and makes working with both XML on the back end and HTML on the front end possible and an effective tool. In this chapter, I will introduce the Document Object Model, explains its use in Web pages, and starts to explore its usage from JavaScript.
Like many Web programmers, you have probably worked with HTML. HTML is how programmers start to work on a Web page; HTML is often the last thing they do as they finish up an application or site, and tweak that last bit of placement, color, or style. And, just as common as using HTML is the misconception about what exactly happens to that HTML once it goes to a browser to render to the screen. Before I dive into what you might think happens -- and why it is probably wrong -- I want you to be clear on the process involved in designing and serving Web pages:
1. Someone (usually you!) creates HTML in a text editor or IDE.
<html>
<head>
<title>Trees, trees, everywhere</title>
</head>
<body>
<h1>Trees, trees, everywhere</h1>
<p>Welcome to a <em>really</em> boring page.
<div>
Come again soon.
<img src="come-again.gif" />
</div>
</body>
</html>
|
<html>
<head>
<title>This is a little tricky</title>
</head>
<body>
<h1>Pay <u>close</u> attention, OK?</h1>
<div>
<p>Welcome to a <em>really</em> boring page.
<p>This p really isn't <em>necessary</em>, but it makes the
<span id="bold-text">structure <i>and</i> the organization</span>
of the page easier to keep up with.</p>
</div>
</body>
</html>
Listing 3. Even trickier nesting of elements
<html>
<head>
<title>Trickier nesting, still</title>
</head>
<body>
<div id="main-body">
<div id="contents">
<table>
<tr><th>Steps</th><th>Process</th></tr>
<tr><td>1</td><td>Figure out the <em>root element</em>.</td></tr>
<tr><td>2</td><td>Deal with the <span id="code">head</span> first,
as it's usually easy.</td></tr>
<tr><td>3</td><td>Work through the <span id="code">body</span>.
Just <em>take your time</em>.</td></tr>
</table>
</div>
<div id="closing">
This link is <em>not</em> active, but if it were, the answers
to this <a href="answers.html"><img src="exercise.gif" /></a> would
be there. But <em>do the exercise anyway!</em>
</div>
</div>
</body>
</html>
|
<DIV id="customer" class="order">some content here</DIV>
|
Chapter 5
Section 5.1: Introduction
Last chapter I introduced the Document Object Model, whose elements work behind the scenes to define your Web pages. This chapter, we'll dive even deeper into the DOM. Learn how to create, remove, and change the parts of a DOM tree, and take the next step toward updating your Web pages on the fly!
If you followed my discussion in this book last chapter, then you got a first-hand look at what goes on when a Web browser displays one of your Web pages. As I explained then, when the HTML and CSS you've defined for your page is sent to a Web browser, it's translated from text to an object model. This is true whether the code is simple or complex, housed all in one file or in separate files.
The browser then works directly with the object model, rather than the text files you supplied. The model the browser uses is called the Document Object Model. It connects objects representing the elements, attributes, and text in your documents. All the styles, values, and even most of the spaces in your HTML and CSS are incorporated into the object model. The specific model for a given Web page is called the page's DOM tree.
Understanding what a DOM tree is, and even knowing how it represents your HTML and CSS, is just the first step in taking control of your Web pages. Next, you need to learn how to work with the DOM tree for a particular Web page. For instance, if you add an element to the DOM tree, that element immediately appears in a user's Web browser -- without the page reloading.
Remove some text from the DOM tree, and that text vanishes from the user's screen. You can change and interact with the user interface through the DOM, which gives you tremendous programming power and flexibility. Once you learn how to work with a DOM tree you've taken a huge leap toward mastering rich, interactive, dynamic Web sites.
Note that the following discussion builds on last chapter's "Exploiting the DOM for Web response;" if you haven't read that tutorial, you might want to do so before you proceed here.
Acronym pronunciation matters
In many ways, the Document Object Model could just as easily have been called the Document Node Model. Of course, most people don't know what the term node means, and "DNM" isn't nearly as easy to pronounce as "DOM," so it's easy to understand why the W3C went with DOM.
Even with that, I, personally, still think that the W3C have made a mistake as well in deriving the acronym DOM from Document Object Model. But, I think the acronym DOM should have been derived from Dynamic Object Model instead, because it is more closely appropriate to the actual nature of the DOM, which is very dynamic in the way it functions as an object. Dynamic object -- get it? It can work with HTML dynamically!
Section 5.2: Cross browser, cross language
The Document Object Model is a W3C standard. Because of that, all modern Web browsers support the DOM, at least to some degree. While there is some variance among browsers, if you use core DOM functionality -- and pay attention to a few special cases and exceptions -- your DOM code will work on any browser in the same way. The code you write to modify a Web page in Opera will work on Apple's Safari, Firefox, Microsoft Internet Explorer, and Mozilla.
The DOM is also a cross-language specification; in other words, you can use it from most of the popular programming languages. The W3C defines several language bindings for the DOM. A language binding is simply an API defined to let you use the DOM for a specific language. For example, you can find well-defined DOM language bindings for C, Java, and JavaScript. So you can use the DOM from any of these languages. Language bindings are also available for several other languages, although many of these are not defined by the W3C, but instead by third parties.
In this chapter I'll focus on the JavaScript bindings into the DOM. That makes sense because most asynchronous application development is based on writing JavaScript code to run in a Web browser. With JavaScript and the DOM, you can modify the user interface on the fly, respond to user events and input, and more -- all using fairly standardized JavaScript.
All that said, I do encourage you to check out the DOM language bindings in other languages. For instance, you can use the Java language bindings to work not only with HTML, but also XML, as I'll discuss in a later chapter. So the lessons you'll learn here apply to far more than HTML, in many more environments than just client-side JavaScript.
The conceptual node
A node is the most basic object type in the DOM. In fact, as you'll see in this chapter, almost every other object defined by the DOM extends the node object. But, before you get too far into semantics, you need to understand the concept that is represented by a node; then, to learn the actual properties and methods of a node is a piece of cake.
In a DOM tree, almost everything you'll come across is a node. Every element is at its most basic level a node in the DOM tree. Every attribute is a node. Every piece of text is a node. Even comments, special characters (like ©, which represents a copyright symbol), and a DOCTYPE declaration (if you have one in your HTML or XHTML) all are nodes. So before I get into the specifics of each of these individual types, you really need to grasp what a node is.
A node is...
In simplest terms, a node is just one single thing in a DOM tree. The vagueness of "thing" is intentional, because that's about as specific as it gets. For example, it's probably not obvious that an element in your HTML, like img, and a piece of text in HTML, like "Scroll down for more details" have much in common. But that's because you're probably thinking about the function of those individual types, and focusing on how different they are.
Consider, instead, that each element and piece of text in a DOM tree has a parent; that parent is either the child of another element (like when an img is nested inside a p element), or is the top-most element in the DOM tree (which is a one-time special case for each document, and is where you use the html element). Also consider that both elements and text have a type. The type for an element is obviously an element; the type for text is text. Each node also has some fairly well-defined structure to it: does it have a node (or nodes) below it, such as child elements? Does it have sibling nodes (nodes "next to" the element or text)? What document does each node belong to?
Obviously, much of this sounds pretty abstract. In fact, it might even seem silly to say that the type of an element is ... well ... an element. However, you need to think a bit abstractly to realize the value of having the node as a common object type.
The common node type
The single task you'll perform more than any other in your DOM code is navigating within the DOM tree for a page. For instance, you might locate a form by its "id" attribute, and then begin to work with the elements and text nested within that form. There will be textual instructions, labels for input fields, actual input elements, and possibly other HTML elements like img elements and links (a elements). If elements and text are completely different types, then you have to write completely different pieces of code to move from one type to another.
Things are different if you use a common node type. In that case you can simply move from node to node, and worry about the type of the node only when you want to do something specific with an element or text. When you just move around in the DOM tree, you'll use the same operations to move to an element's parent -- or its children -- as you would with any other type of node. You only have to work specifically with a node type, like an element or text, when you require something specific from a certain type of node, like an element's attributes. Thinking about each object in the DOM tree simply as a node allows you to operate much more simply. With that in mind, I'll look next at exactly what the DOM Node construct has to offer, starting with properties and methods.
Section 5.3: Properties of a node
You'll want to use several properties and methods when you work with DOM nodes, so let's consider them first. The key properties of a DOM node are:
1. nodeName reports the name of the node (see more below).
2. nodeValue:gives the "value" of the node (see more below).
3. parentNode returns the node's parent. Remember, every element, attribute, and text has a parent node.
4. childNodes is a list of a node's children. When working with HTML, this list is only useful when you're dealing with an element; text nodes and attribute nodes don't have any children.
5. firstChild is just a shortcut to the first node in the childNodes list.
6. lastChild is another shortcut, this time to the last node in the childNodes list.
7. previousSibling returns the node before the current node. In other words, it returns the node that precedes the current one, in this node's parent's childNodes list (if that was confusing, re-read that last sentence).
8. nextSibling is similar to the previousSibling property; it turns the next node in the parent's childNodes list.
9. attributes is only useful on an element node; it returns a list of an element's attributes.
10. The few other properties really apply to more generic XML documents, and aren't of much use when you work with HTML-based Web pages.
For those of you who want to work with PHP, check this out: DOMDocument
Unusual properties
// These first two lines get the DOM tree for the current Web page,
// and then the <html> element for that DOM tree
var myDocument = document;
var htmlElement = myDocument.documentElement;
// What's the name of the <html> element? "html"
alert("The root element of the page is " + htmlElement.nodeName);
// <head> element
var headElement = htmlElement.getElementsByTagName("head")[0];
if (headElement != null)
{
// the name of the <head> element: nodeName returns "head"
alert("We found the head element, named " + headElement.nodeName);
// Print out the title of the page
var titleElement = headElement.getElementsByTagName("title")[0];
if (titleElement != null)
{
// The text will be the first child node of the <title> element
var titleText = titleElement.firstChild;
// We can get the text of the text node with nodeValue
alert("The page title is '" + titleText.nodeValue + "'");
}
// After <head> is <body>
var bodyElement = headElement.nextSibling;
while (bodyElement.nodeName.toLowerCase() != "body")
{
bodyElement = bodyElement.nextSibling;
}
// We found the <body> element...
// We'll do more when we know some methods on the nodes.
}
|
// These first two lines get the DOM tree for the current Web page,
// and then the <html> element for that DOM tree
var myDocument = document;
var htmlElement = myDocument.documentElement;
// What's the name of the <html> element? "html"
alert("The root element of the page is " + htmlElement.nodeName);
// Look for the <head> element
let headElement = htmlElement.getElementsByTagName("head")[0];
if (headElement != null)
{
// the name of the <head> element: nodeName returns "head"
alert("We found the head element, named " + headElement.nodeName);
// Print out the title of the page
var titleElement = headElement.getElementsByTagName("title")[0];
if (titleElement != null)
{
// The text will be the first child node of the <title> element
var titleText = titleElement.firstChild;
// We can get the text of the text node with nodeValue
alert("The page title is '" + titleText.nodeValue + "'");
}
// After <head> is <body>
var bodyElement = headElement.nextSibling;
while (bodyElement.nodeName.toLowerCase() != "body")
{
bodyElement = bodyElement.nextSibling;
}
// We found the <body> element...
// Remove all the top-level <img> elements in the body
if (bodyElement.hasChildNodes())
{
for (i=0; i<bodyElement.childNodes.length; i++)
{
var currentNode = bodyElement.childNodes[i];
if (currentNode.nodeName.toLowerCase() == "img")
{
bodyElement.removeChild(currentNode);
}
}
}
}
|
<html>
<head>
<title>JavaScript and the DOM</title>
<script language="JavaScript">
function test()
{
// These first two lines get the DOM tree for the current Web page,
// and then the rest of the <html> elements for that DOM tree
var myDocument = document;
var htmlElement = myDocument.documentElement;
// documentElement returns the <html> element of the document as
// a node name, for example, the following variable x contains: HTML
// var x = document.documentElement.nodeName;
// What's the name of the <html> element? "html"
alert("The root element of the page is " + htmlElement.nodeName);
// Look for the <head> element
var headElement = htmlElement.getElementsByTagName("head")[0];
if (headElement != null)
{
// the name of the <head> element: nodeName returns "head"
alert("We found the head element, named " + headElement.nodeName);
// Print out the title of the page
var titleElement = headElement.getElementsByTagName("title")[0];
if (titleElement != null)
{
// The text will be the first child node of the <title> element
var titleText = titleElement.firstChild;
// We can get the text of the text node with nodeValue
alert("The page title is '" + titleText.nodeValue + "'");
}
// After <head> is <body>
var bodyElement = headElement.nextSibling;
while (bodyElement.nodeName.toLowerCase() != "body")
{
bodyElement = bodyElement.nextSibling;
}
// We found the <body> element...
// Remove all the top-level <img> elements in the body
if (bodyElement.hasChildNodes())
{
for (i=0; i<bodyElement.childNodes.length; i++)
{
var currentNode = bodyElement.childNodes[i];
if (currentNode.nodeName.toLowerCase() == "img")
{
bodyElement.removeChild(currentNode);
}
}
}
}
}//end rest()
</script>
</head>
<body>
<p>JavaScript and DOM are a perfect match. </p>
<p>test() above removes all top-level <img> elements in the body!</p>
<img src="http://www.example.com/Image/any_image.jpg" />
<input type="button" value="Test me!" onClick="test();" />
</body>
</html>
|
var pElement = myDocument.createElement("p");
var text = myDocument.createTextNode("Here's some text in a p element.");
pElement.appendChild(text);
bodyElement.appendChild(pElement);
Now we can use the above code like this:
// assuming we have an html markup document like this:
<html>
<head></head>
<body id="mybody">
<div id="mydiv">
</div>
</body>
</html>
// The following two lines create the DOM tree document object for the above Web page
var myDocument = document;
var htmlElement = myDocument.documentElement; // returns <html> element as a node name
// Next, get the <head> element
var headElement = htmlElement.getElementsByTagName("head")[0];
// Next, get the <body> element
var bodyElement = headElement.nextSibling;
// Create a <p> element
var pElement = myDocument.createElement("p");
// To add text to the <p> element (pElement), we must create a text node first.
// This code creates a text node containing some text:
var text = myDocument.createTextNode("Here's some text in a p element.");
// Now that we got a text node containing some text, we can add that node
// to the <p> element (pElement)
pElement.appendChild(text);
// So now <p> element looks something like this in markup:
// <p>Here's some text in a p element.</p>
// Now all we have to do is to append the <p> element containing actual text to
// the body element
bodyElement.appendChild(pElement);
// after the above code is run we have an html markup document
// that looks something like this:
<html>
<head></head>
<body id="mybody">
<div id="mydiv">
</div>
<p>Here's some text in a p element.</p>
</body>
</html>
Notice that above, it appends the paragraph: <p>Here's some text in a p element.</p> to the end of the existing code: in this case, the <div></div> block. There are ways to append before or after certain node as well. For more, please check out tutorials on the Web as well as the rest of this chapter explaining a few text node methods. For example:
1. appendData(text) adds the text you supply to the end of the text node's existing text.
2. insertData(position, text) allows you to insert data in the middle of the text node. It inserts the text you supply at the position indicated.
3. replaceData(position, length, text) removes the characters starting from the position indicated, of the length indicated, and puts the text you supply to the method in the place of the removed text.
For now, let's continuing on our DOM tree description.
Once you've used the document element to get access to a Web page's DOM tree, you're ready to start working with elements, attributes, and text directly, beginning with element node next.
Element nodes
// Remove all the top-level <img> elements in the body
if (bodyElement.hasChildNodes())
{
for (i=0; i < bodyElement.childNodes.length; i++)
{
var currentNode = bodyElement.childNodes[i];
if (currentNode.nodeName.toLowerCase() == "img")
{
bodyElement.removeChild(currentNode);
}
}
}
|
// Remove all the top-level <img> elements in the body
var imgElements = bodyElement.getElementsByTagName("img");
for (i=0; i < imgElements.length; i++)
{
var imgElement = imgElements.item[i];
bodyElement.removeChild(imgElement);
}
|
// Remove all the top-level <img> elements in the body
var imgElements = bodyElement.getElementsByTagName("img");
for (i=0; i < imgElements.length; i++)
{
var imgElement = imgElements.item[i];
// Print out some information about this element
var msg = "Found an img element!";
var atts = imgElement.attributes;
for (j=0; j < atts.length; j++)
{
var att = atts.item(j);
msg = msg + "\n " + att.nodeName + ": '" + att.nodeValue + "'";
}
alert(msg);
bodyElement.removeChild(imgElement);
}
|
let pElements = bodyElement.getElementsByTagName("p");
for (i=0; i < pElements.length; i++)
{
var pElement = pElements.item(i);
var text = pElement.firstChild.nodeValue;
alert(text);
}
|
let someNode = document.documentElement.firstChild;
if (someNode.nodeType == Node.ELEMENT_NODE)
{
alert("We've found an element node named " + someNode.nodeName);
}
else if (someNode.nodeType == Node.TEXT_NODE)
{
alert("It's a text node; the text is " + someNode.nodeValue);
}
else if (someNode.nodeType == Node.ATTRIBUTE_NODE)
{
alert("It's an attribute named " + someNode.nodeName
+ " with a value of '" + someNode.nodeValue + "'");
}
|
That was pertain to Internet Explorer 6 only and later Internet Explorer versions have been ported to work with the said problem. That was for educational purpose only!
Section 5.8: Conclusion.Chapter 6
Section 6.1: Introduction
Combine the Document Object Model (DOM) with JavaScript code to create interactive Ajax applications. In previous chapters in this book, you examined the concepts involved in DOM programming -- how the Web browser view a Web page as a tree -- and you should now understand the programming structures used in the DOM. In this chapter, you put all of this knowledge into practice and build a simple Web page that has some nice effects, all created using JavaScript to manipulate the DOM, without ever reloading or refreshing the page.
You've had two full chapters of introduction to the Document Object Model, or DOM; you should be pretty comfortable with how the DOM works by now. In this chapter, you'll put that understanding into practice. You'll develop a basic Web application with a user interface that changes based on user actions -- of course, you'll use the DOM to handle changing that interface. By the time you're finished with this chapter, you'll have put most of the techniques and concepts you've learned about the DOM into practice.
I assume that you've followed along for the last two chapters; if you haven't, review them to get a solid understanding of the DOM and of how Web browsers turn the HTML and CSS you supply them into a single tree structure that represents a Web page. All of the DOM principles that I've talked about so far will be used in this chapter to build a working -- albeit somewhat simple -- DOM-based dynamic Web page. If at any point in this chapter you get stuck, you can simply stop and review the earlier two chapters, and come back.
Section 6.2: Getting started with the sample application
A note on the code
To keep the focus specifically on the DOM and JavaScript code, I've been somewhat sloppy and have written HTML with inline style (like the align attribute on the h1 and p elements, for example). While this is acceptable for trying things out, I recommend that you take the time to put all your styles into external CSS stylesheets for any production applications you develop.
Let's start out by putting together a very basic application, and then adding a little DOM magic. In keeping with the idea that the DOM can move things around on a Web page without submitting a form -- thus making it a perfect companion for Ajax -- let's build a simple page that shows nothing but a plain old top hat, and a button labeled Hocus Pocus! (Can you guess where this will go?)
The initial HTML
Listing 1 shows the HTML for this page; it's just a body with a heading and a form, along with a simple image and a button that you can push.
Listing 1. The HTML for the sample application
<html>
<head>
<title>Magic Hat</title>
</head>
<body>
<h1 align="center">Welcome to the DOM Magic Show!</h1>
<form name="magic-hat">
<p align="center">
<img src="topHat.gif" />
<br />
|
<html>
<head>
<title>Magic Hat</title>
</head>
<body>
<h1 align="center">Welcome to the DOM Magic Show!</h1>
<form name="magic-hat">
<p align="center">
<img src="topHat.gif" id="topHat" />
<br />
|
<html>
<head>
<title>Magic Hat</title>
<script language="JavaScript">
function showRabbit()
{
var hatImage = document.getElementById("topHat");
}
</script>
</head>
<body>
<h1 align="center">Welcome to the DOM Magic Show!</h1>
<form name="magic-hat">
<p align="center">
<img src="topHat.gif" id="topHat" />
<br />
|
<html>
<head>
<title>Magic Hat</title>
<script language="JavaScript">
function showRabbit()
{
let hatImage = document.getElementById("topHat");
let newImage = document.createElement("img");
newImage.setAttribute("src", "rabbit-hat.gif");
}
</script>
</head>
<body>
<h1 align="center">Welcome to the DOM Magic Show!</h1>
<form name="magic-hat">
<p align="center">
<img src="topHat.gif" id="topHat" />
<br />
|
<html>
<head>
<title>Magic Hat</title>
<script language="JavaScript">
function showRabbit()
{
let hatImage = document.getElementById("topHat");
let newImage = document.createElement("img");
newImage.setAttribute("src", "rabbit-hat.gif");
let imgParent = hatImage.parentNode;
imgParent.insertBefore(newImage, hatImage);
imgParent.removeChild(hatImage);
}
</script>
</head>
<body>
<h1 align="center">Welcome to the DOM Magic Show!</h1>
<form name="magic-hat">
<p align="center">
<img src="topHat.gif" id="topHat" />
<br />
|
<html>
<head>
<title>Magic Hat</title>
<script language="JavaScript">
function showRabbit()
{
let hatImage = document.getElementById("topHat");
let newImage = document.createElement("img");
newImage.setAttribute("src", "rabbit-hat.gif");
let imgParent = hatImage.parentNode;
imgParent.replaceChild(newImage, hatImage);
}
</script>
</head>
<body>
<h1 align="center">Welcome to the DOM Magic Show!
<form name="magic-hat">
<p align="center">
<img src="topHat.gif" id="topHat" />
<br />
|
<html>
<head>
<title>Magic Hat</title>
<script language="JavaScript">
function showRabbit()
{
let hatImage = document.getElementById("topHat");
hatImage.setAttribute("src", "rabbit-hat.gif");
}
</script>
</head>
<body>
<h1 align="center">Welcome to the DOM Magic Show!</h1>
<form name="magic-hat">
<p align="center">
<img src="topHat.gif" id="topHat" />
<br />
|
<html>
<head>
<title>Magic Hat</title>
<script language="JavaScript">
function showRabbit()
{
let hatImage = document.getElementById("topHat");
hatImage.setAttribute("src", "rabbit-hat.gif");
}
</script>
</head>
<body>
<h1 align="center">Welcome to the DOM Magic Show!
<form name="magic-hat">
<p align="center">
<img src="topHat.gif" id="topHat" />
<br />
|
function showRabbit()
{
let hatImage = document.getElementById("topHat");
hatImage.setAttribute("src", "rabbit-hat.gif");
let button = document.getElementById("hocusPocus");
}
|
function showRabbit()
{
let hatImage = document.getElementById("topHat");
hatImage.setAttribute("src", "rabbit-hat.gif");
let button = document.getElementById("hocusPocus");
button.setAttribute("value", "Get back in that hat!");
}
|
<html>
<head>
<title>Magic Hat</title>
<script language="JavaScript">
function showRabbit()
{
let hatImage = document.getElementById("topHat");
hatImage.setAttribute("src", "rabbit-hat.gif");
let button = document.getElementById("hocusPocus");
button.setAttribute("value", "Get back in that hat!");
}
</script>
</head>
<body>
<h1 align="center">Welcome to the DOM Magic Show!</h1>
<form name="magic-hat">
<p align="center">
<img src="topHat.gif" id="topHat" />
<br />
|
function hideRabbit()
{
let hatImage = document.getElementById("topHat");
hatImage.setAttribute("src", "topHat.gif");
let button = document.getElementById("hocusPocus");
button.setAttribute("value", "Hocus Pocus!");
}
|
The sample application at this point has one big problem: even though the label of the button changes, the action that occurs when you click that button does not.
Fortunately, you can change the event -- the action that occurs -- when a user clicks the button using the DOM. So if the button reads 'Get back in that hat!, you want it to run hideRabbit() when it's clicked. Conversely, once the rabbit is hidden, the button returns to running showRabbit().
In addition to the onclick property, there's a method intended to be used to add an event handler, like onClick or onBlur; it's unsurprisingly called addEventListener(). Unfortunately, Microsoft Internet Explorer 8 and earlier don't support this method; however, Internet Explorer 9 and onward will properly support this method. So if you use it in your JavaScript, millions of Internet Explorer 8.0 or earlier, users are going to get nothing from your page other than an error (and probably some ideas about complaints).
You can get the same results using Javascript event property called onclick, which does work on all versions of Internet Explorer.
If you look at the HTML, you'll see that the event you deal with here is onClick. In JavaScript, you can reference this event using the onclick property of a button. (Note that in HTML, the property is generally referred to as onClick, with a capital C, and in JavaScript, it's onclick, all lowercase.) So you can change the event that's run on a button: you just assign a new function to the onclick property.
<html>
<head>
<title>Magic Hat</title>
<script language="JavaScript">
function showRabbit()
{
let hatImage = document.getElementById("topHat");
hatImage.setAttribute("src", "rabbit-hat.gif");
let button = document.getElementById("hocusPocus");
button.setAttribute("value", "Get back in that hat!");
button.onclick = hideRabbit;
}
function hideRabbit()
{
let hatImage = document.getElementById("topHat");
hatImage.setAttribute("src", "topHat.gif");
let button = document.getElementById("hocusPocus");
button.setAttribute("value", "Hocus Pocus!");
button.onclick = showRabbit;
}
</script>
</head>
<body>
<h1 align="center">Welcome to the DOM Magic Show!</h1>
<form name="magic-hat">
<p align="center">
<img src="topHat.gif" id="topHat" />
<br />
|
Now let's briefly touch on the issue of Internet Explorer version 8.0 and earlier not supporting addEventListener() while Internet Explorer version 9.0 or later will support this addEventListener() method just fine.
Let's illustrate the same code above using addEventListener() method on Internet Explorer version 9.0 or later.
Listing 10(a). Using addEventListener() method on Internet Explorer version 9.0 or later
<html>
<head>
<title>Magic Hat</title>
<script language="JavaScript">
function showRabbit()
{
let hatImage = document.getElementById("topHat");
hatImage.setAttribute("src", "rabbit-hat.gif");
let button = document.getElementById("hocusPocus");
button.setAttribute("value", "Get back in that hat!");
// hideRabbit() is a listener for click events registered using
// addEventListener(). "click" is the event name
// A click on the "Hocus Pocus!" button bubbles up to the handler
// and runs hideRabbit()
button.addEventListener("click", hideRabbit);
}
function hideRabbit()
{
let hatImage = document.getElementById("topHat");
hatImage.setAttribute("src", "topHat.gif");
let button = document.getElementById("hocusPocus");
button.setAttribute("value", "Hocus Pocus!");
// showRabbit() is a listener for click events registered using
// addEventListener(). "click" is the event name
// A click on the "Hocus Pocus!" button bubbles up to the handler
// and runs showRabbit()
button.addEventListener("click", showRabbit);
}
</script>
</head>
<body>
<h1 align="center">Welcome to the DOM Magic Show!</h1>
<form name="magic-hat">
<p align="center">
<img src="topHat.gif" id="topHat" />
<br />
|
Hopefully, you can use both the examples using JavaScript property called onclick and as well as using JavaScript method addEventListener() in your Javascript code because nowaday no one in the right mind would still be using Internet Explorer 8.0 or lower. So it's safe to assume that everybody are using and will still continue to use Internet Explorer version 9.0 or later.
Section 6.8: Conclusion.Chapter 7
Section 7.1: Introduction
First of all, XML is an acronym for Extensible Markup Language (or XHTML)--an extension of the Hypertext Markup Language (or HTML).
You really can't do any significant programming today without running across XML. Whether you're a Web page designer considering the move to XHTML, a Web programmer working with JavaScript, a server-side programmer using deployment descriptors and data binding, or a back-end developer investigating XML-based databases, the extensible markup language is everywhere. It's no surprise, then, that XML is considered one of the core technologies that underlies Ajax.
function callServer()
{
// Get the city and state from the Web form
let firstName = document.getElementById("firstName").value;
let lastName = document.getElementById("lastName").value;
let street = document.getElementById("street").value;
let city = document.getElementById("city").value;
let state = document.getElementById("state").value;
let zipCode = document.getElementById("zipCode").value;
// Build the URL to connect to
let url = "/scripts/saveAddress.php?firstName=" + escape(firstName) +
"&lastName=" + escape(lastName) + "&street=" + escape(street) +
"&city=" + escape(city) + "&state=" + escape(state) +
"&zipCode=" + escape(zipCode);
// Open a connection to the server
xmlHttp.open("GET", url, true);
// Set up a function for the server to run when it's done
xmlHttp.onreadystatechange = confirmUpdate;
// Send the request
xmlHttp.send(null);
}
|
<firstName>Larry</firstName>
<lastName>Gullahorn</lastName>
<street>9018 Heatherhorn Drive</street>
<city>Rowlett</city>
<state>Texas</state>
<zipCode>75080</zipCode>
|
<address>
<firstName>Larry</firstName>
<lastName>Gullahorn</lastName>
<street>9018 Heatherhorn Drive</street>
<city>Rowlett</city>
<state>Texas</state>
<zipCode>75080</zipCode>
</address>
|
Both of these will probably require you to actually talk to a human being, so fair warning! Seriously, if it's important that you be able to send data as XML, most script writers will oblige you; so just finding a script that will accept XML shouldn't be that hard. However, you'still need to make sure that the your format matches what the script expects.
Most of the situations, the party that you're dealing with usually have some sort of documentation outlining the procedures of their API. For example, if you're trying to request an API from payment processors like PayPal, Stripe, Mastercard, Visa, etc, or from other parties as well, such as financial instutitions for requesting stock trading purposes, they're already layout their API documentation in a clear and concise for you to use to make requests. All you have to do is follow their guideline and make requests. You don't need to talk to a human being, except if you have further questions.
Most of the documentation will specify exactly what you should and shouldn't do to make the request. For the sake of this tutorial, suppose that the server accepts data like this:
<profile>
<firstName>Larry</firstName>
<lastName>Gullahorn</lastName>
<street>9018 Heatherhorn Drive</street>
<city>Rowlett</city>
<state>Texas</state>
<zip-code>75080</zip-code>
</profile>
|
function callServer()
{
// Get the city and state from the Web form
let firstName = document.getElementById("firstName").value;
let lastName = document.getElementById("lastName").value;
let street = document.getElementById("street").value;
let city = document.getElementById("city").value;
let state = document.getElementById("state").value;
let zipCode = document.getElementById("zipCode").value;
let xmlString = "<profile>" +
" <firstName>" + escape(firstName) + "</firstName>" +
" <lastName>" + escape(lastName) + "</lastName>" +
" <street>" + escape(street) + "</street>" +
" <city>" + escape(city) + "</city>" +
" <state>" + escape(state) + "</state>" +
" <zip-code>" + escape(zipCode) + "</zip-code>" +
"</profile>";
// Build the URL to connect to
let url = "/scripts/saveAddress.php";
// Open a connection to the server
xmlHttp.open("POST", url, true);
// Tell the server you're sending it XML
xmlHttp.setRequestHeader("Content-Type", "text/xml");
// Set up a function for the server to run when it's done
xmlHttp.onreadystatechange = confirmUpdate;
// Send the request
xmlHttp.send(xmlString);
}
|
let xmlString = "<profile>" +
" <firstName>" + escape(firstName) + "</firstName>" +
" <lastName>" + escape(lastName) + "</lastName>" +
" <street>" + escape(street) + "</street>" +
" <city>" + escape(city) + "</city>" +
" <state>" + escape(state) + "</state>" +
" <zip-code>" + escape(zipCode) + "</zip-code>" +
"</profile>";
|
Chapter 8
Section 8.1: Introduction
In the last chapter, you saw how your Ajax apps can format requests to a server in XML. You also saw why, in most cases, that isn't a good idea. This chapter focuses on something that often is a good idea: returning XML responses to a client.
I don't really enjoy writing tutorials that are primarily about something that you shouldn't do. Most of the time, it's a pretty silly type of thing to write. I spend half the chapter explaining something, just so I can spend the rest of the chapter explaining what a bad idea it is to use the techniques you've just learned about. Such was the case, to a large degree, with last chapter's discussion, which taught you how to use XML as the data format for your Ajax apps' requests.
Hopefully, this chapter will redeem the time you spent learning about XML requests. In Ajax apps, while there are very few reasons to use XML as the sending data format, there are a lot of reasons why you might want a server to send XML back from a server, to a client. So everything you learned about XML in the last chapter will definitely start to have some value in this chapter.
Section 8.2: Server Back-End
Before you dive into the technical details of getting an XML response from a server, you need to understand why it's such a good idea for a server to send XML in response to a request (and how that's different from a client sending that request in XML).
Clients speak in name/value pairs
As you'll recall from the last chapter, clients don't need to use XML in most cases because they can send requests using name/value pairs. So you might send a name like this: name=jennifer. You can stack those up by simply adding an ampersand (&) between successive name/value pairs, like this: name=jennifer&job=president. Using simple text and these name/value pairs, clients can send requests with multiple values to a server easily. There's rarely a need for the additional structure (and overhead) that XML provides.
In fact, almost all the reasons you'd need to send XML to a server can be grouped into two basic categories:
1. The server only accepts XML requests. In these cases, you don't have a choice. The basics in last chapter's discussion should give you all the tools you need to send these sorts of requests.
2. You're calling a remote API that only accepts XML or SOAP requests. This is really just a specialized case of the previous point, but it's worth mentioning on its own. If you want to use the APIs from Google or Amazon in an asynchronous request, there are some particular considerations. I'll look at those, and a few examples of making requests to APIs like this, in next chapter's discussion.
Servers can't send name/value pairs (in a standard way)
When you send name/value pairs, the Web browser sending the requests and the platform responding to that request and hosting a server program cooperate to turn those name/value pairs into data that a server program can work with easily. Practically every server-side technology -- from Java servlets to PHP to Perl to Ruby on Rails -- allows you to call a variety of methods to get at values based on a name. So getting the name attribute is trivial.
This isn't the case going in the other direction. If a server replied to an app with the string name=jennifer&job=president, the client has no standardized, easy way to break up the two name/value pairs, and then break each pair into a name and value. You'll have to parse the returned data manually. If a server returns a response made up of name/value pairs, that response is no easier (or harder) to interpret than a response with elements separated by semicolons, or pipe symbols, or any other nonstandard formatting character.
Give me some space!
In most HTTP requests, the escape sequence %20 is used to represent a single space. So the text "Live Together, Die Alone" is sent over HTTP as Live%20Together,%20Die%20Alone.
What that leaves you with, then, is no easy way to use plain text in your responses and have the client get that response and interpret it in a standard way, at least when the response contains multiple values. If your server simply sent back the number 42, say, plain text would be great. But what about if it's sending back the latest ratings for the TV shows Lost, Alias, and Six Degrees, all at once? While you can chose many ways to send this response using plain text (see Listing 1 for a few examples), none are particularly easy to interpret without some work by the client, and none are standardized at all.
Listing 1. Server response for TV ratings (various versions)
show=Alias&ratings=6.5|show=Lost&ratings=14.2|show=Six%20Degrees&ratings=9.1
Alias=6.5&Lost=14.2&Six%20Degrees=9.1
Alias|6.5|Lost|14.2|Six%20Degrees|9.1
Even though it's not too hard to figure out how to break up these response strings, a client will have to parse and split the string up based on the semicolons, equal signs, pipes, and ampersands. This is hardly the way to write robust code that other developers can easily understand and maintain.
Enter XML
When you realize that there's no standard way for a server to respond to clients with name/value pairs, the reasoning behind using XML becomes pretty clear. When sending data to the server, name/value pairs are a great choice because servers and server-side languages can easily interpret the pairs; the same is true for using XML when returning data to a client. You saw the use of the DOM to parse XML in several earlier chapters, and will see how JSON provides yet another option to parse XML in a future chapter. And on top of all that, you can treat XML as plain text, and get values out of it that way. So there are several ways to take an XML response from a server, and, with fairly standard code, pull the data out and use it in a client.
As an added bonus, XML is generally pretty easy to understand. Most people who program can make sense of the data in Listing 2, for example.
Listing 2. Server response for TV ratings (in XML)
<ratings>
<show>
<title>Alias</title>
<rating>6.5</rating>
</show>
<show>
<title>Lost</title>
<rating>14.2</rating>
</show>
<show>
<title>Six Degrees</title>
<rating>9.1</rating>
</show>
</ratings>
|
<ratings>
<show>
<title>Alias</title>
<rating>6.5</rating>
</show>
<show>
<title>Lost</title>
<rating>14.2</rating>
</show>
<show>
<title>Six Degrees</title>
<rating>9.1</rating>
</show>
</ratings>
|
function updatePage()
{
if (request.readyState == 4)
{
if (request.status == 200)
{
let response = request.responseText;
// response has the XML response from the server
alert(response);
}
}
}
|
<ratings><show><title>Alias</title><rating>6.5</rating>
</show><show><title>Lost</title><rating>14.2</rating></show><show>
<title>Six Degrees</title><rating>9.1</rating></show></ratings>
|
function updatePage()
{
if (request.readyState == 4)
{
if (request.status == 200)
{
var xmlDoc = request.responseXML;
// work with xmlDoc using the DOM
}
}
}
|
function updatePage()
{
if (request.readyState == 4)
{
if (request.status == 200)
{
var xmlDoc = request.responseXML;
var showElements = xmlDoc.getElementsByTagName("show");
}
}
}
|
function updatePage()
{
if (request.readyState == 4)
{
if (request.status == 200)
{
let xmlDoc = request.responseXML;
var showElements = xmlDoc.getElementsByTagName("show");
for (let x = 0; x < showElements.length; x++)
{
// We know that the first child of show is title,
//and the second is rating
let title = showElements[x].childNodes[0].value;
let rating = showElements[x].childNodes[1].value;
// Now do whatever you want with the show title and ratings
}
}
}
}
|
<?php
// Connect to a MySQL database
$conn = @mysql_connect("mysql.myhost.com", "username", "secret-password");
if (!conn)
die("Error connecting to database: " . mysql_error());
if (!mysql_select_db("television", $conn))
die("Error selecting TV database: " . mysql_error());
// Get ratings for all TV shows in database
$select = 'SELECT title, rating';
$from = ' FROM ratings';
$queryResult = @mysql_query($select . $from);
if (!$queryResult)
die("Error retrieving ratings for TV shows.');
// Let the client know we're sending back XML
header("Content-Type: text/xml");
echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
echo "<ratings>";
while ($row = mysql_fetch_array($queryResult))
{
$title = $row['title'];
$rating = $row['rating'];
echo "<show>
echo "<title>" . $title . "</title>";
echo "<rating>" . $rating . "</rating>";
echo "</show>";
}
echo "</ratings>";
mysql_close($conn);
?>
|
Chapter 9
Section 9.1: Introduction
Making asynchronous requests isn't just about talking to your own server-side programs. You can also communicate with public APIs like those from Google or Amazon, and add more functionality to your Web applications than just what your own scripts and server-side programs provide. In this chapter, I will teache you how to make and receive requests and responses from public APIs like those supplied by Google.
So far in this book, the focus was exclusively on situations in which your client Web pages make requests to your server-side scripts and programs. This is how probably 80 to 90 percent of Ajax applications -- asynchronous Web applications that use the XMLHttpRequest object -- work. However, there is a fairly serious limitation in this approach: you're limited by your own ingenuity and programming skills, or at least by the ingenuity and programming skills of the programmers on your team, in your company.
Almost certainly, sometimes you find'll that you really want to do something, but you don't have the technical knowledge necessary to achieve that goal. Perhaps you don't know some piece of syntax, or how to come up with the right algorithm. In other cases, you might not have the data or resources (either people-resources or data-resources) to fill your needs. It's in these cases that you might find yourself thinking, "Gee, if I could just use that other person's code!" This chapter is meant to address that particular case.
Open source scripts and programs
Before I get into the meat of this chapter -- using public APIs in your Web applications -- it's worth mentioning the existence of open source scripts and programs. Without getting too deeply into detail, open source is a term used to describe code that can be, to some degree, freely used and reused in your own applications. Consult Resources for relevant links, but at a 10,000-foot view, you can take open source code that someone else has written, and simply drop it into your own environment, without charge or (much) restriction.
If you make use of open source code, sometimes you'll have to add some extra documentation to your applications, or perhaps contribute changes you make to the open source program or script back to the community. Whatever the particulars of the program that you use, the end result is that you can use code that you didn't have to write, and perhaps wouldn't have been able to write without a lot of help and resources that you don't have. Projects like Apache make it easy to take advantage of the work that others have done -- and don't worry; they want you to use their work!
Articles and tutorials online
It would also be pretty silly writing a book about Ajax and not mention the wealth of resources, from articles to tutorials to white papers, available on the Internet. There are literally hundreds of thousands of pieces of instruction online, and you could probably find close to a thousand articles about Ajax -- and one author by the name of Brett McLaughlin has written countless articles and books--most of them available online for free. Most of these articles have working code, examples, downloads, and all sorts of other goodies available for your use.
If you don't have the ability to code the server-side program or script you want to use, or can't find an open source program or script to do what you need, hop over to Google and try entering in a basic description of what you're looking for. You'll often find an article, or tip, or some other snippet online that might help you do just what you need. Hop over to developerWorks and do the same; often, you'll find exactly the piece of code, or even entire script, that you were looking for, complete with helpful comments and a description of how it works.
Section 9.2: Using public APIs
Many times, you'll face a problem that isn't just technical. You don't need help writing a particular script or piece of code; rather, you need data or resources that you simply don't have. In these cases, even if a tutorial or open source script were available to help you, you'd still need more. Consider, for example, a case in which you want to place a search engine on your Web page. That presumes that you have the data that you want to search -- but what if you want to search beyond the data your company or organization has available?
In cases where you are limited not by technical ability, but by data, a public API might help you solve your problem. A public API allows you to use a program hosted on someone else's servers, using someone else's data. In general, the API itself defines how you interact with the program. For instance, a public API to the Google search engine would var you make search requests, but Google's code would search Google's data, and return the results to your program. You not only get the benefit of someone else's technical skills in writing these programs, but you also get the benefit of data stores far beyond your or your company's ability to support.
Getting set up to use the Google Ajax Search API
Google remains, arguably, the breakthrough application of the online era. Grandmothers and four-year-olds know about Google, even if they don't understand how anything else online works. Google runs such a massively popular and useful search engine, and seems so committed to providing (mostly) free services that it's no surprise that it has a public API available for you to use in your own programs. In this section, you'll get set up to use the Google API, and prepare to figure out exactly how you can make an asynchronous application talk to Google.
Getting a developer key from Google
This chapter will focus specifically on Google's Ajax Search API. You can find out more online about this particular API by visiting the Google Ajax Search API home page, which is shown in Figure 1.
Figure 1. Google's Ajax Search API page
Your first step is to click the Sign up for a Google AJAX Search API key link. This will take you to a page where you can sign up to use the Google API. You'll need to accept some terms of use -- all of which are pretty harmless, as far as I can tell -- and supply the URL of the Web site where your application will run (see Figure 2).
Figure 2. Signing up for Google's Ajax Search API
What URL should I use?
The URL that Google asks for is more or less actually the domain where you run your site. You only need to be more specific if your site uses a subdomain or a particular path within a larger domain.
Once you've read the agreement and checked the checkbox, enter in your URL, click Generate API Key, and wait a second or two. At this point, you'll have to log in to Google, or create an account. This is a pretty standard process, and you should be able to handle it on your own. Once you're finished, you'll get a nice reply screen back, which gives you a very long key, repeats back your URL, and even gives you a sample page. The key will look something like this:
ABQIAAAAjtuhyCXrSHOFSz7zK0f8phSA9fWLQO3TbB2M9BRePlYkXeAu8lHeUgfgRs0eIWUaXg
Section 9.3: Google's API documentation
Before you start to use the key you've just been assigned, you take some time to check out Google's API documentation (there's a link at the bottom of the page that supplied your key. Even though you can get a really good start through this chapter, you'll find that Google's API documentation is a good read, and will probably give you some interesting ideas for how you can use Google on your own site, in your own unique applications.
The simplest Google search Web application
To get you used to seeing what's possible, let's take the sample Web page that Google provides, change it up just a bit, and see how it works.
Creating a search box
Listing 1 shows a pretty simple Web page; go ahead and type it into your favorite editor, save it, and upload it to the domain or URL that you supplied to Google in the previous section.
Listing 1. The HTML for a simple Google search application
<html>
<head>
<title>My Google AJAX Search API Applicationlt;/title>
<link href="http://www.google.com/uds/css/gsearch.css"
type="text/css" rel="stylesheet" />
<script
src="http://www.google.com/uds/api?file=uds.js&v=1.0&key=YOUR KEY HERE"
type="text/javascript"> </script>
<script language="Javascript" type="text/javascript">
function OnLoad()
{
// Create the Google search control
let searchControl = new GSearchControl();
// These allow you to customize what appears in the search results
let localSearch = new GlocalSearch();
searchControl.addSearcher(localSearch);
searchControl.addSearcher(new GwebSearch());
searchControl.addSearcher(new GvideoSearch());
searchControl.addSearcher(new GblogSearch());
// Tell Google your location to base searches around
localSearch.setCenterPoint("Dallas, TX");
// "Draw" the control on the HTML form
searchControl.draw(document.getElementById("searchcontrol"));
}
</script>
</head>
<body onload="OnLoad()">
<div id="searchcontrol" />
</body>
</html>
|
function OnLoad()
{
// Create the Google search control
let searchControl = new GSearchControl();
// These allow you to customize what appears in the search results
let localSearch = new GlocalSearch();
searchControl.addSearcher(localSearch);
searchControl.addSearcher(new GwebSearch());
searchControl.addSearcher(new GvideoSearch());
searchControl.addSearcher(new GblogSearch());
// Tell Google your location to base searches around
localSearch.setCenterPoint("Dallas, TX");
// "Draw" the control on the HTML form
searchControl.draw(document.getElementById("searchcontrol"));
searchControl.execute("Christmas Eve");
}
|
function OnLoad()
{
// Create the Google search control
let searchControl = new GSearchControl();
...
}
|
function OnLoad()
{
// Create the Google search control
let searchControl = new GSearchControl();
// These allow you to customize what appears in the search results
let localSearch = new GlocalSearch();
...
// Tell Google your location to base searches around
localSearch.setCenterPoint("Dallas, TX");
...
}
|
function OnLoad()
{
// Create the Google search control
let searchControl = new GSearchControl();
// These allow you to customize what appears in the search results
let localSearch = new GlocalSearch();
searchControl.addSearcher(localSearch);
searchControl.addSearcher(new GwebSearch());
searchControl.addSearcher(new GvideoSearch());
searchControl.addSearcher(new GblogSearch());
// Tell Google your location to base searches around
localSearch.setCenterPoint("Dallas, TX");
...
}
|
function OnLoad()
{
// Create the Google search control
let searchControl = new GSearchControl();
// These allow you to customize what appears in the search results
let localSearch = new GlocalSearch();
searchControl.addSearcher(localSearch);
searchControl.addSearcher(new GwebSearch());
searchControl.addSearcher(new GvideoSearch());
searchControl.addSearcher(new GblogSearch());
// Tell Google your location to base searches around
localSearch.setCenterPoint("Dallas, TX");
// "Draw" the control on the HTML form
searchControl.draw(document.getElementById("searchcontrol"));
searchControl.execute("Christmas Eve");
}
|
<script src="http://www.google.com/uds/api?file=uds.js&v=1.0&key=[YOUR GOOGLE KEY]"
type="text/javascript"> </script>
|
// Create the Google search control
let searchControl = new GSearchControl();
|
<div id="searchcontrol" />
|
Chapter 10
Section 10.1: Introduction
Plain text and XML are both data formats that you can use for sending and receiving information in your asynchronous applications. This chapter looks at another useful data format, JavaScript Object Notation (JSON), and how it makes moving data and objects around in your applications easier.
Obviously, XML has received its fair share of press (both negative and positive), and it's no surprise that it shows up in Ajax applications. You can review earlier chapters in this book to see how XML provides an alternative data format, for example, to refresh your memory:
<request>
<firstName>John</firstName>
<lastName>Doe</lastName>
<email>john@doe.com</email>
</request>
|
JSON (JavaScript Object Notation) is a lightweight data-interchange format built-in the JavaScript language already and you don't need a plugin to use it. It is easy for humans to read and write. It is easy for machines to parse and generate. It is based on a subset of the JavaScript Programming Language, Standard ECMA-262 3rd Edition - December 1999. JSON is a text format that is completely language independent but uses conventions that are familiar to programmers of the C-family of languages, including C, C++, C#, Java, JavaScript, Perl, TCL, and many others. These properties make JSON an ideal data-interchange language.
You'll see that most of today's programming languages use JSON data format as well in addition to their native data formats.
At its simplest, JSON allows you to transform a set of data represented in a JavaScript object into a string that you can easily pass from one function to another, or -- in the case of asynchronous applications -- from a Web client to a server-side program. The string looks a little odd (you'll see some examples in just a moment), but it's easily interpreted by JavaScript, and JSON allows you to represent structures more complex than name/value pairs. For instance, you can represent arrays and complex objects, rather than just simple lists of keys and values.
{ "firstName" : "John" }
|
firstName=John
|
{ "firstName" : "John", "lastName" : "Doe", "email" : "john@doe.com" }
|
{
"people":
[
{ "firstName" : "John", "lastName" : "Doe", "email" : "john@doe.com" },
{ "firstName" : "Jane", "lastName" : "Doe", "email" : "jane@doe.com" },
{ "firstName" : "Mary", "lastName" : "Public", "email" : "mary@abc.com" }
]
}
|
{
"programmer":
[
{ "firstName" : "John", "lastName" : "Doe", "email" : "john@doe.com" },
{ "firstName" : "Jane", "lastName" : "Doe", "email" : "jane@doe.com" },
{ "firstName" : "Mary", "lastName" : "Public", "email" : "mary@abc.com" }
],
"author":
[
{ "firstName" : "Isaac", "lastName" : "Asimov", "genre" : "science fiction" },
{ "firstName" : "Tad", "lastName" : "Williams", "genre" : "fantasy" },
{ "firstName" : "Frank", "lastName" : "Peretti", "genre" : "christian fiction" }
],
"musician":
[
{ "firstName" : "Eric", "lastName" : "Clapton", "instrument" : "guitar" },
{ "firstName" : "Sergei", "lastName" : "Rachmaninoff", "instrument" : "piano" }
]
}
|
let people =
{
"programmer":
[
{ "firstName" : "John", "lastName" : "Doe", "email" : "john@doe.com" },
{ "firstName" : "Jane", "lastName" : "Doe", "email" : "jane@doe.com" },
{ "firstName" : "Mary", "lastName" : "Public", "email" : "mary@abc.com" }
],
"author":
[
{ "firstName" : "Isaac", "lastName" : "Asimov", "genre" : "science fiction" },
{ "firstName" : "Tad", "lastName" : "Williams", "genre" : "fantasy" },
{ "firstName" : "Frank", "lastName" : "Peretti", "genre" : "christian fiction" }
],
"musician":
[
{ "firstName" : "Eric", "lastName" : "Clapton", "instrument" : "guitar" },
{ "firstName" : "Sergei", "lastName" : "Rachmaninoff", "instrument" : "piano" }
]
};
|
That's all there is to it!
Now you've got a string of text that you can use anywhere you like -- you could use it as the request string in an Ajax application, for instance:
// see url timeStamp explanation later near the end of chapter 11
let url = "/cgi-local/server.php?timeStamp=" + new Date().getTime();
request.open("POST", url, true);
request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
request.send("newJSONtext);
Let's see some brief JSON data structure examples:
A common use of JSON is to exchange data to/from a web server.
When sending data to a web server, the data has to be a string. And the most popular string format is the JSON string data structure.
Before a string is sent to the server, it needs to convert from a JavaScript object into a string with JSON.stringify().
Stringify a JavaScript Object
Imagine we have this object in JavaScript:
var obj = { name: "John", age: 30, city: "New York" };
Use the JavaScript function JSON.stringify() to convert it into a string.
var myJSON = JSON.stringify(obj);
The result will be a string following the JSON notation. So myJSON is now a JSON string (or more specifically a JSON string object), and ready to be sent to a server:
// obj is a Javascript array object, myJSON is a JSON data
var obj = { name: "John", age: 30, city: "New York" };
var myJSON = JSON.stringify(obj);
document.getElementById("demo").innerHTML = myJSON;
Chapter 11
Section 11.1: Introduction
In the last chapter, you learned how to take an object in JavaScript and convert it into a JSON representation. That format is an easy one to use for sending (and receiving) data that maps to objects, or even arrays of objects. In this final chapter of this book, you'll learn how to handle data sent to a server in the JSON format and how to reply to scripts using the same format.
Section 11.2: JSON's real value
As discussed in the previous chapter, JSON is a useful format for Ajax applications because it allows you to convert between JavaScript objects and string values quickly. Because Ajax apps are best suited to send plain text to server-side programs and receive plain text in return, an API that generates text is almost always preferable over an API that doesn't; further, JSON allows you to work with native JavaScript objects and not worry about how those objects will be represented.
So the biggest value of JSON is that you can work with JavaScript as JavaScript, not as a data-format language. All the things you learn about using JavaScript objects can be applied to your code without worrying about how those objects will be converted to text. Then, you make a simple JSON method call, for example:
var myObjectInJSON = JSON.stringify(myObject);
and you're ready to send the resulting text onto a server.
The above example, 'myObject' is a Javascript array object.
Getting JSON to the server
Sending JSON to the server isn't particularly difficult, but it is crucial, and you still have a few choices to make. However, once you've already chosen to use JSON, the choices are a lot simpler and quite a bit more limited, so there's not as much to think or worry about. The bottom line is you just need to get your JSON string to the server, preferably as quickly and as simply as possible. For example:
// see url timeStamp explanation later near the end of chapter 11
let url = "/cgi-local/server.php?timeStamp=" + new Date().getTime();
request.open("POST", url, true);
request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
request.send("myObjectInJSON);
let people =
{
"programmer":
[
{ "firstName": "John", "lastName":"Doe", "email": "john@doe.com" },
{ "firstName": "Jane", "lastName":"Doe", "email": "jane@doe.com" },
{ "firstName": "Mary", "lastName":"Public", "email": "mary@abc.com" }
],
"author":
[
{ "firstName": "Isaac", "lastName": "Asimov", "genre": "science fiction" },
{ "firstName": "Tad", "lastName": "Williams", "genre": "fantasy" },
{ "firstName": "Frank", "lastName": "Peretti", "genre": "christian fiction" }
],
"musician":
[
{ "firstName": "Eric", "lastName": "Clapton", "instrument": "guitar" },
{ "firstName": "Sergei", "lastName": "Rachmaninoff", "instrument": "piano" }
]
};
|
let url = "organizePeople.php?people=" + JSON.stringify(people);
xmlHttp.open("GET", url, true);
xmlHttp.onreadystatechange = updatePage;
xmlHttp.send(null);
|
let url = "organizePeople.php?people=" + escape(JSON.stringify(people));
request.open("GET", url, true);
request.onreadystatechange = updatePage;
request.send(null);
|
let url = "organizePeople.php?timeStamp=" + new Date().getTime();
request.open("POST", url, true);
request.onreadystatechange = updatePage;
request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
request.send(JSON.stringify(people));
|
Most of this code should be familiar to you from chapter 3, which focuses on sending POST requests. The request is opened using POST instead of GET, and the Content-Type header is set to let the server know what sort of data it should expect. In this case, that's application/x-www-form-urlencoded, which lets the server know you're just sending across text like it would get from a normal HTML form. You could also use "application/json" and it would work just fine.
send() contains the JSON strings 'people' converted to a JSON data format using the JSON string function stringify() to send it as a JSON string format.
One other quick note is that the URL has the current time appended to it. That ensures that the request isn't cached after it's sent the first time but is recreated and resent each time this method is called; the URL will be subtly different because of the changing time stamp. This is a common trick to ensure that POSTing to a script actually repeatedly generates a new request each time, and the Web browser doesn't try and cache responses from the server.Parsing JSON data structure.
By the way, did you see me mentioning somewhere either in this book or somewhere else that Javascript is the most difficult language of all the languages out there? Well, if you haven't seen my comment about how hard it is to master Javascript language, take this as a friendly warning. It is very hard to master all the nooks and crannies of Javascript language. It is very complex.
Sure a lot of programmers out there, including myself, don't know everything that Javscript has to offer; and therefore, they can get by just fine using what they already know and if you don't know what others know, it's not the end of the world. That's how I approach to learning Javascrdipt. Learn it little by little! And hey, if you don't know, then so beit!
Having said that, let's take just a fragment of the data structure in listing 1 and see what we can make sense of it.
// you can approach this as some sort of a multi-dimensional array
// it's an array that contains JSON objects
"programmer":
[
{ "firstName": "John", "lastName":"Doe", "email": "john@doe.com" },
{ "firstName": "Jane", "lastName":"Doe", "email": "jane@doe.com" },
{ "firstName": "Mary", "lastName":"Public", "email": "mary@abc.com" }
],
/**
* As you can see above, 'programmer' is the key and on the
* right side is the value of the array, in this case, square brackets [].
*
* But inside [] we have three array elements, and each array element is
* grouped by {}.
*
* So to acces the first element:
* { "firstName": "John", "lastName":"Doe", "email": "john@doe.com" }
* do this:
* programmer[0]
*
* To acces the second element:
* { "firstName": "Jane", "lastName":"Doe", "email": "jane@doe.com" }
* do this:
* programmer[1]
*
* To acces the third element:
* { "firstName": "Mary", "lastName":"Public", "email": "mary@abc.com" }
* do this:
* programmer[2]
*
* However, those three element contains an array of their own: this is called
* multi-dimensional array or array of arrays.
*
* So to access a multi-dimensional array, you could use a brute force like this:
*
* programmer[0].firstName // "John"
*
* programmer[0].lastName // "Doe"
*
* programmer[0].email // "john@doe.com"
*
* programmer[1].firstName // "Jane"
*
* programmer[1].lastName // "Doe"
*
* programmer[1].email // "jane@doe.com"
*
* programmer[2].firstName // "Mary"
*
* programmer[2].lastName // "Public"
*
* programmer[3].email // "mary@abc.com"
*
* Or you could use for() loops as in the following.
*
* Notice that for (i in ....)
* with i automatically initialized to 0 by default!
*/
Now that a partial illustration of JSON data structure has been explained, let's put the full data structure listed in listing 1 to work. It should be easy now. All the JSON data structure belong to a node called 'people' and we'll use for (... in ...) loop to iterate through this node:
document.write("<table width='100%'>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Email</th>
</tr>");
// now iterate through JSON data structure in listing 2 with n = 0 by default
// when n = 0 it is pointing to 'programmer', n = 1 it is pointing to 'author',
// n = 2 it is pointing to 'musician'.
// notice that we're not doing anything through this loop.
// we're only running through the loop to allow the inner loop run its course.
for (n in peole)
{
// iterate through JSON data structure in listing 1 with i = 0 by default
for (i in people.programmer)
{
/**
* did I mentioned somewhere that Javascript language is the most difficult
* language out there?
*
* an example of that is right here where I try to make sense of the data
* structure sent as a JSON encoded data and trying to parse that data and
* iterate through for() loops to access the parsed data using Javascript.
*
* basically, I'm STUMP!!! and I gave up!!!
*
* I have no idea how to access the parsed JSON data structure.
*
* so I'll leave it to you as an exercise to do, and hopefully you know
* a better way of doing it than I do.
*/
// iterate through JSON data structure in listing 1 with inner loop
for (j = 0; j < 4; ++j)
{
if (j = 0)
{
if (i = 0)
{
/**
* when i = 0, and j = 0, firstName[0] = 'John'
*/
let firstName[i] = people.programmer[i].firstName[j];
}
else if (i = 1)
{
/**
* when i = 1, and j = 0, firstName[1] = 'Jane'
*/
let firstName[i] = people.programmer[i].firstName[j];
}
else if (i = 2)
{
/**
* when i = 2, and j = 0, firstName[2] = 'Mary'
*/
let firstName[i] = people.programmer[i].firstName[j];
}
}
else if (j = 1)
{
if (i = 0)
{
/**
* when i = 0, and j = 1, lastName[0] = 'Doe'
*/
let lastName[i] = people.programmer[i].latName[j];
}
else if (i = 1)
{
/**
* when i = 1, and j = 1, lastName[1] = 'Doe'
*/
let lastName[i] = people.programmer[i].lastName[j];
}
else if (i = 2)
{
/**
* when i = 2, and j = 1, lastName[2] = 'Public'
*/
let lastName[i] = people.programmer[i].lastName[j];
}
}
else if (j = 2)
{
if (i = 0)
{
/**
* when i = 0, and j = 2, email[0] = 'john@doe.com'
*/
let email[i] = people.programmer[i].email[j];
}
else if (i = 1)
{
/**
* when i = 1, and j = 2, email[1] = 'jane@doe.com'
*/
let email[i] = people.programmer[i].email[j];
}
else if (i = 2)
{
/**
* when i = 2, and j = 2, email[2] = 'mary@abc.com'
*/
let email[i] = people.programmer[i].email[j];
// I left out Joe Sixpack to save space!
}
} // end else if (j = 2)
} // end for (j = 0)
} // end for (i in ...)
/**
* now you have three arrays: firstName, lastName, email.
*
* and each array contains first names, last names, and emails for
* the three programmers.
*
* I hope you can make sense of it and can use it accordingly.
*
* I'll leave it as an exercise for you to do.
*
* below is my attempt to make use of the data.
* however, you might know a better way to do than this:
*/
document.write("<tr>");
// I could just as well use lastName.length or email.length. same result!
for (i = 0; i < firstName.length; ++i)
{
document.write("<td>" + firstName[i] + "</td>");
document.write("<td>" + lastName[i] + "</td>");
document.write("<td>" + email[i] + "</td>");
}
document.write("</tr>");
} // end for (n in ...)
document.write("</table>");
// the result from the above output looks like this:
First Name Last Name Email
---------- -------------- ---------------
John Doe john@doe.com
Jane Doe jane@doe.com
Mary Public mary@abc.com
Now despite my pre-emptive warning of how hard it is to program in Javascript, the above example doesn't seem that hard, or does it?
Anyhow, let's see another example of how to use complex JSON data structure similar to listing 1 but with some more arrays within the already existed arrays. In other words, it's the JSON objects mix with JSON arrays. But you can think of it as a multi-dimensional arrays. It is somewhat complex but not too complex.
Listing 2. A somewhat complex JavaScript object in JSON format
let dealer =
{
"name" : "John Doe",
"city" : "Miami",
"state" : "FL",
"inventory" :
[
{ "make" : "GM", "model" : ["Denali", "Yukon", "Sierra"], "color": "grey" },
{ "make" : "Ford", "model" : ["Focus", "F150": "Mustang" ], "color": "green" },
{ "make" : "Toyota", "model" : ["Corolla", "Tundra", "Teurcel"], "color": "blue" }
]
};
|
Now with the somewhat complex JSON data structure have been layout, we access it as in the following.
// to access the owner is easy using brute force:
dealer[0].name; // John Doe
dealer[0].city; // Miami
dealer[0].state; // FL
// notice that the array indexes always start with 0 pointing to
// the 1st element 'make', and iterating to 2nd element 'model', and third 'color'
// now iterate through JSON data structure in listing 2 with i = 0 by default
for (i in dealer.inventory)
{
// x = 'For GM:', 'For Ford: ', 'For Toyota:'
let x = "For " + dealer.inventory[i].make + ":";
// now iterate through JSON inner array data structure in listing 2
// as you can see, if you have other inner arrays, say color, you can
// actually make it as array of colors, i.e., red, white, blue, etc.
// or "color" : ["red", "white", "blue"] and iterate the same way as shown here.
// but instead of "model", use "color" in place. very easy!
for (j in dealer.inventory[i].model)
{
// you might find a more useful way to do with x, such as store it in a db
x += dealer.inventory[i].model[j];
document.write(x);
}
// the result from the above output looks like this:
For GM:
Denali
Yukon
Sierra
For Ford:
Focus
F150
Mustang
For Toyota:
Corolla
Tundra
Teurcel
I left out color in the above example, but you can handle it by yourself easily! With examples shown thus far, you can actually find your own unique ways to format your data structure and parse it accordingly in a more useful way. The possibilities are there for you to take advantage of using what already illustrated.
Section 11.5: Interpreting JSON on the server
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
StringBuffer jb = new StringBuffer();
String line = null;
try
{
BufferedReader reader = request.getReader();
while ((line = reader.readLine()) != null)
jb.append(line);
}
catch (Exception e)
{
//report an error
}
try
{
JSONObject jsonObject = new JSONObject(jb.toString());
}
catch (ParseException e)
{
// crash and burn
throw new IOException("Error parsing JSON request string");
}
// Work with the data using methods like...
// int someInt = jsonObject.getInt("intParamName");
// String someString = jsonObject.getString("stringParamName");
// JSONObject nestedObj = jsonObject.getJSONObject("nestedObjName");
// JSONArray arr = jsonObject.getJSONArray("arrayParamName");
// etc...
}
|
The following are just end of book bonus materials to help you get some more ideas using JSON data structure.
The most popular method of sending/receiving resources to and from the server among the financial transactions (particularly credit card transactions) is CURL. Most of the payment providers (such as Visa, Mastercard, PayPal, Stripe, Authorize.NET, etc.) use CURL to send/receive resources to and from the server. And for that reason, we'll begin bonus section with CURL.
<?php
/**
* $Url = 'https://www.example.com/charge.php
*
* $param can be passed in from the caller as an array:
*
* [
* "amount" => $100.00,
* "currency" => "usd",
* "description" => "Customer order number: 12345",
* "customer" => customerID_12345
* ]
*/
public function request($Url, $param)
{
$curl = curl_init();
$opt = array();
if (count($param) > 0)
{
$field = array();
foreach ($param as $key => $value)
{
$field[] = $key . '=' . urlencode($value);
}
$postField = implode( $field, '&' );
$opt[CURLOPT_POST] = 1; // set CURLOPT_POST to 1 for 'POST'ing to the server
// Contains the associative array of the fields that we want to post.
// The array keys are named after the name of the form fields.
// CURLOPT_POSTFIELDS => $postField contains name/value pairs.
$opt[CURLOPT_POSTFIELDS] = $postField;
}
else
{
throw new Exception("Try to post data to server without data.");
}
// set CURLOPT_URL to the UTF8-encoded string
$opt[CURLOPT_URL] = utf8_encode($Url);
$opt[CURLOPT_RETURNTRANSFER] = true; // setting it to true enables it to return the response
$opt[CURLOPT_CONNECTTIMEOUT] = 30;
$opt[CURLOPT_TIMEOUT] = 80;
$opt[CURLOPT_RETURNTRANSFER] = true;
curl_setopt_array($curl, $opt);
// $result is the response from the server
// it will be returned to the caller as an array with $result is the first element,
// and the response code information in $code
$result = curl_exec($curl);
$errno = curl_errno($curl);
if (result === false)
{
$errno = curl_errno($curl);
$message = curl_error($curl);
curl_close($curl);
return array($message); // you need to output this error message in your calling code
}
// To get additional information about the request,
// we use the curl_getinfo($c, CURLINFO_HTTP_CODE) command that enables us to receive
// important technical information about the response,
// including the status code (200 for success) and the size of the downloaded file.
$code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
curl_close($curl);
// $result is the response from the server
// it will be returned to the caller as an array with $result is the first element,
// and the response code information in $code
return array($result, $code);
}
?>
Once you send data to the server -- in other words, once you made a request to the server -- you need a server-side script like PHP to response to it and parse it and process it and then send back the response to the client.
If you look closely in the above example, it is a server-side language PHP acting as a client-side script using CURL to make a request to the server-side language, PHP in this case: charge.php.
PHP is sort of both a server-side and a client-side language -- making use CURL, which stands for "Client URL", as a client-side language.
Now the whole example above is a client-side script in PHP, making a request to a server-side language, also PHP in this case: charge.php.
Now you'll have to write your own PHP server-side language containing a script called charge.php and perform the necessary tasks according to your objective.
Next up is the client-server interaction that you'd learned throughout this book.
Here is an example of interacting with client and server scripts.
But first, let's create a server-side PHP script to send back data to the client-side Javascript.
File name: test.php.
<?php
// now create a PHP object containing data to send back to client script: Javascript
$myObj->name = "John Doe";
$myObj->email = "john@doe.com";
$myObj->occupation = "Programmer";
/**
* now format that data into a JSON data structure.
*
* notice that in PHP, you can just declare a variable and a property and use them
* together like above and it becomes an object.
*
* also, remember that JSON data structure in Javascript is slightly different than
* the one used by PHP, but they both are treated in the same manner.
*
* Okay, let's go on with PHP version of JSON data structure.
*
* below will encode the above PHP object into a JSON format that will look like the following:
*
* {"name" : "John Doe", "email" : "john@doe.com", "occupation" : "Programmer"}
*/
$myJSON = json_encode($myObj);
/**
* below will brute force send the encoded JSON data object ($myJSON) above to the client
*
* now the client can parse this encoded JSON data object using a function called parse()
* see the client script below on how to parse this encoded JSON data object ($myJSON)
*/
echo $myJSON;
?>
Now that we have a server-side script ready and waiting to response to the client-side script requesting data, we can go ahead and request data from the server. Here is a JavaScript on the client side, using an AJAX call to request a PHP file from the server containing a file called test.php in the example above. This should looks familiar to you from earlier chapters:
<script language="javascript" type="text/javascript">
/* Create a new XMLHttpRequest object to talk to the Web server */
var xmlHttp = false;
if (document.window.XMLHttpRequest)
{
//creating a non-MS browser object
xmlHttp = new XMLHttpRequest();
}
else if (document.window.ActiveXObject)
{
// this is the newer MS browser object and not even
// bother to test for older versions
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
}
else
{
document.write("unknown browser");
}
if (!xmlHttp)
{
alert("Error initializing XMLHttpRequest!");
}
xmlhttp.onreadystatechange = function()
{
// object variable 'this' refers to an xmlHttpRequest object
// you could also just use the already initialized variable 'xmlhttp' object
if (this.readyState == 4 && this.status == 200)
{
var myObj = JSON.parse(this.responseText);
/**
* now variable myObj contains the decoded Javascript data object that looks
* like this:
*
* {"name" : "John Doe", "email" : "john@doe.com", "occupation" : "Programmer"}
*
* now that looks just like the encoded JSON data structure.
* yes, that is Javascript object.
*
* now you can access the decoded Javascript data object by referring to its
* object keys.
* for example: myObj.name, myObj.email, myObj.occupation, etc.
*
* below, assuming you have an HTML element that has an id attribute called "test",
* you can populate data like the following:
*/
document.getElementById("test").innerHTML = myObj.name;
}
};
// right here, we are requesting server-side script: test.php
// notice also that we're using GET instead of POST
// we're not sending anything to the server -- we're only requesting from the server
// if you want to use POST instead of GET it is very easy to modify.
// see earlier examples and as well as examples shown later!
// of course, the complete url is required for both "GET" and "POST", for example,
// if we have this: http://www.example.com/test.php
// open("GET", "http://www.example.com/test.php", true)
xmlhttp.open("GET", "test.php", true);
// after that, we can just go ahead and send the request to the server
xmlhttp.send();
</script>
As always when working with JSON and Javascript, whether with arrays or non-arrays, you need to make use of two special functions called parse() to parse the JSON encoded data structure and stringify() to convert the JavaScript object into JSON data structure. Please Google them to learn more about them. They are very powerful functions for using JSON data with Javascript language.
We can use arrays in PHP to convert to JSON data format as well by using PHP function json_encode():
File name: example.php.
<?php
// now create a PHP array object containing data to send back to client script: Javascript
$myArr = ["John Doe", "Jane Doe", "Mary Public", "Joe Sixpack"];
/**
* now after the below code is executed, the above data is converted into
* a JSON array data structure that looks like this:
*
* ["John Doe", "Jane Doe", "Mary Public", "Joe Sixpack"]
*
* as you can see, hardly any difference from the PHP array structure.
* nevertheless, it was a conversion from PHP data structure to a JSON data structure.
*/
$myJSON = json_encode($myArr);
/**
* the below code will brute force send the encoded JSON data object above to the client
*
* now the client can parse this encoded JSON data object using a function called parse()
* see the client script below on how to parse this encoded JSON data object
*/
echo $myJSON;
?>
Now all we have to do is make an AJAX call to request a PHP file from the server containing a file called example.php in the example above. This should looks like the following:
<script language="javascript" type="text/javascript">
/* Create a new XMLHttpRequest object to talk to the Web server */
var xmlHttp = false;
if (document.window.XMLHttpRequest)
{
//creating a non-MS browser object
xmlHttp = new XMLHttpRequest();
}
else if (document.window.ActiveXObject)
{
// this is the newer MS browser object and not even
// bother to test for older versions
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
}
else
{
document.write("unknown browser");
}
if (!xmlHttp)
{
alert("Error initializing XMLHttpRequest!");
}
xmlhttp.onreadystatechange = function()
{
// object variable 'this' refers to an xmlHttpRequest object
// you could also just use the already initialized variable 'xmlhttp' object
if (this.readyState == 4 && this.status == 200)
{
var myObj = JSON.parse(this.responseText);
/**
* now variable myObj contains the decoded JSON array object.
* in other words, a PHP array object was converted/parsed to
* a JSON array object.
*
* remember that responseText contains a JSON array object
* that was converted from a PHP array object which looks like this:
*
* ["John Doe", "Jane Doe", "Mary Public", "Joe Sixpack"]
*
* so the PHP array object above is converted to this:
*
* ["John Doe", "Jane Doe", "Mary Public", "Joe Sixpack"]
*
* as you can see, hardly any difference at all between PHP and JSON
* array object.
*
* so responseText contains the latter JSON array object.
* and then myObj above was decoded using JSON.parse() to result
* in the following:
*
* ["John Doe", "Jane Doe", "Mary Public", "Joe Sixpack"]
*
* are you still with me? have I lost you? yes, the back and forth
* conversion is a dizzing matter! and the results look the same!
* so is there a need to convert from one language to the next?
*
* the answer is: yes!
* it has to do with the browser needing to know what kind of data
* it is transporting to and from the server.
*
* when using JSON.parse() on a JSON derived/converted data from
* an array, the method parse() will return a JavaScript array exactly
* as shown above, or i.e., myObj[0], myObj[1], myObj[2], etc.,
* instead of a JavaScript object like myObj.name, myObj.email, etc.
*
* pew!!! very dizzing to explain as well!
*
* now you can access the encoded JSON array data object by referring to its
* index keys. for example: myObj[0], myObj[1], myObj[2], etc.
*
* or specifically: myObj[0] = "John Doe", myObj[1] = "Jane Doe",
* myObj[2] = "Mary Public", myObj[3] = "Joe Sixpack"
*
* below, assuming you have an HTML element that has an id attribute
* called "example", you can populate data like the following:
*/
// will output 'Mary Public'
document.getElementById("example").innerHTML = myObj[2]; // myObj[2] = "Mary Public"
}
};
// right here, we are requesting server-side script: example.php
// notice also that we're using GET instead of POST.
// we're not sending anything to the server -- we're only requesting from the server
// of course, the complete url is required for both "GET" and "POST", for example,
// if we have this: http://www.example.com/example.php
// open("GET", "http://www.example.com/example.php", true)
xmlhttp.open("GET", "example.php", true);
// we can just send the request to the server.
// notice that 'null' is not needed: send(null)
xmlhttp.send();
</script>
PHP is a server side programming language, and can be used to access a database.
Imagine you have a database on your server, and you want to send a request to it from the client where you ask for the 10 first rows in a table called "customer".
On the client, make a JSON object that describes the name of the table, and the numbers of rows you want to return.
Before you send the request to the server, convert the JSON object into a string and send it as a parameter to the url of the PHP page using "GET". For example, use JSON.stringify() to convert the JavaScript object into JSON:
<script language="javascript" type="text/javascript">
/* Create a new XMLHttpRequest object to talk to the Web server */
var xmlHttp = false;
if (document.window.XMLHttpRequest)
{
//creating a non-MS browser object
xmlHttp = new XMLHttpRequest();
}
else if (document.window.ActiveXObject)
{
// this is the newer MS browser object and not even
// bother to test for older versions
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
}
else
{
document.write("unknown browser");
}
if (!xmlHttp)
{
alert("Error initializing XMLHttpRequest!");
}
/* declare some object variables */
let obj = {"table" : "customer", "limit" : 10};
// you could format this as a valid url to use with POST instead of GET
var dbParam = JSON.stringify(obj);
xmlhttp.onreadystatechange = function()
{
// object variable 'this' refers to an xmlHttpRequest object
// you could also just use the already initialized variable 'xmlhttp' object
if (this.readyState == 4 && this.status == 200)
{
/**
* now assuming you have an HTML element that has an id attribute called "db",
* you can populate data like the following:
*/
document.getElementById("db").innerHTML = this.responseText);
}
/**
* now the JSON data (myObj) received from the PHP file looks like this:
*
* [
* { "name" : "John Doe" }, { "name" : "Jane Doe" },
* { "name" : "Mary Public" }, { "name" : "Joe Sixpack"}, {..... }
* ]
*
* of course, it was sent in a long string with no space between them; except,
* between first names and last names. self-explanatory!
*
* now you can access the above JSON data object by looping through the result.
* for example:
*
* convert the result received from the PHP file into a JavaScript object,
* or in this case, a JavaScript array using JSON.parse() to convert the JSON into
* a JavaScript object.
*
* of course, you need to prepare the xmlHttp variable before using it.
* when you get to the code that looks like the following, use a for() loop.
* self-explanatory!
*
* xmlhttp.onreadystatechange = function()
* {
* if (xmlhttp.readyState == 4 && this.status == 200)
* {
* var myObj = JSON.parse(xmlhttp.responseText);
* // right here where you convert the above JSON data into Javascript object
* for (x in myObj)
* {
* txt += myObj[x].name + "<br>";
* }
*
* //document.getElementById("db").innerHTML = txt;
* document.write(txt);
* }
* };
*
* the output data looks like the following:
*
* John Doe
* Jane Doe
* Mary Public
* Joe Sixpack
* ...
* ...
*/
};
// you could format it as a POST instead of GET and send it
// as a POST by removing a GET parameter
// of course, the complete url is required for both "GET" and "POST", for example,
// if we have this: http://www.example.com/db.php
// open("GET", "http://www.example.com/db.php?x=" + dbParam, true)
// right here, we are requesting server-side script: db.php
xmlhttp.open("GET", "db.php?x=" + dbParam, true);
// we can just send the request to the server.
// notice that 'null' is not needed: send(null)
xmlhttp.send();
</script>
Here is the PHP server-side script that responses to the client script above:
File name: db.php.
<?php
// tell the client we're sending a JSON data
header("Content-Type: application/json; charset=UTF-8");
// now retrieve an HTTP request using GET containing x
// and decode the JSON data structure into a PHP array object
$obj = json_decode($_GET["x"], false);
// now $obj contains this data: [ "table" => "customer", "limit" => 10 ]
// make sure you get proper connection parameters from your db hosting server
try
{
$conn = new PDO("mysql:host=$hostingserver;dbname=$databaseName",
$username, $password,);
}
catch (PDOException $e)
{
echo 'ERROR: Cannot connect to the server: ' . $e->getMessage();
}
try
{
$stmt = $conn->prepare("SELECT name FROM $obj->table LIMIT $obj->limit");
$result = $stmt->execute();
// another popular option is FETCH_OBJ
$output = $result->setFetchMode(PDO::FETCH_ASSOC);
// right here where we will brute force send the database data to the client.
// before we do that we need to format the data into a JSON data format:
echo json_encode($output);
// the rest are just optional illustrations
// right here, if you want to know how many rows selected
$rowcount = $result->rowCount();
if ($rowcount > 0)
{
// output # of rows selected
echo ($rowcount . ' rows');
}
// if you want to iterate through the $result
while ($row = $result->fetch())
{
$name = $row["name"];
echo $name;
}
}
catch (PDOException $e)
{
echo 'ERROR: Cannot retrieve data: ' . $e->getMessage();
}
?>
When sending data to the server, it is often best to use the HTTP POST method.
To send AJAX requests using the POST method, specify the method, and the correct header.
The data sent to the server must now be an argument to the send() method.
This should looks very familiar to you from earlier chapters:
File name: txt.js.
<script language="javascript" type="text/javascript">
/* Create a new XMLHttpRequest object to talk to the Web server */
var xmlHttp = false;
if (document.window.XMLHttpRequest)
{
//creating a non-MS browser object
xmlHttp = new XMLHttpRequest();
}
else if (document.window.ActiveXObject)
{
// this is the newer MS browser object and not even
// bother to test for older versions
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
}
else
{
document.write("unknown browser");
}
if (!xmlHttp)
{
alert("Error initializing XMLHttpRequest!");
}
/* declare and initialize some object variables */
var obj, dbParam, xmlhttp, myObj, x, txt = "";
obj = {"table" : "customer", "limit" : 10};
dbParam = JSON.stringify(obj);
xmlhttp.onreadystatechange = function()
{
// object variable 'this' refers to an xmlHttpRequest object
// you could also just use the already initialized variable 'xmlhttp' object
if (this.readyState == 4 && this.status == 200)
{
myObj = JSON.parse(this.responseText);
for (x in myObj)
{
txt += myObj[x].name + "<br>";
}
/**
* now assuming you have an HTML element that has an id attribute called "txt",
* you can populate data like the following:
*/
document.getElementById("txt").innerHTML = txt);
}
/**
* now the JSON data (myObj) received from the PHP file looks like this:
*
* [
* { "name" : "John Doe" }, { "name" : "Jane Doe" },
* { "name" : "Mary Public" }, { "name" : "Joe Sixpack"}, {..... }
* ]
*
* of course, it was sent in a long string with no space between them; except,
* between first names and last names. self-explanatory!
*
* now you can access the above JSON data object by looping through the result.
* for example:
*
* convert the result received from the PHP file into a JavaScript object,
* or in this case, a JavaScript array using JSON.parse() to convert the JSON into
* a JavaScript object.
*
* of course, you need to prepare the xmlHttp variable before using it.
* when you get to the code that looks like the following, use a for() loop.
* self-explanatory!
*
* xmlhttp.onreadystatechange = function()
* {
* if (xmlhttp.readyState == 4 && this.status == 200)
* {
* var myObj = JSON.parse(xmlhttp.responseText);
* // right here where you convert the above JSON data into Javascript object
* for (x in myObj)
* {
* txt += myObj[x].name + "<br>";
* }
*
* //document.getElementById("txt").innerHTML = txt;
* document.write(txt);
* }
* };
*
* the output data looks like the following:
*
* John Doe
* Jane Doe
* Mary Public
* Joe Sixpack
* ...
* ...
*/
};
// right here, we are requesting server-side script: txt.php
xmlhttp.open("POST", "txt.php", true);
// of course, the complete url is required for both "GET" and "POST", for example,
// if we have this: http://www.example.com/txt.php
// open("POST", "http://www.example.com/txt.php", true)
// we need to prepare the header properly before sending a POST
xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
// we can just send the request to the server. notice that instead of 'null', we are
// posting the long string to the server with a key/value pair, with x is the key.
xmlhttp.send("x=" + dbParam);
</script>
Here is the PHP server-side script that responses to the client POST script above. Notice that the only difference in the PHP file earlier that used a $_GET is the method for getting the transferred data.
Here, we use $_POST instead of $_GET.
File name: txt.php.
<?php
// tell the client we're sending a JSON data
header("Content-Type: application/json; charset=UTF-8");
// now retrieve an HTTP request using $_POST containing x
// and decode the JSON data structure into a PHP array object
$obj = json_decode($_POST["x"], false);
// now $obj contains this data: [ "table" => "customer", "limit" => 10 ]
// make sure you get proper connection parameters from your db hosting server
try
{
$conn = new PDO("mysql:host=$hostingserver;dbname=$databaseName",
$username, $password,);
}
catch (PDOException $e)
{
echo 'ERROR: Cannot connect to the server: ' . $e->getMessage();
}
try
{
$stmt = $conn->prepare("SELECT name FROM $obj->table LIMIT $obj->limit");
$result = $stmt->execute();
// another popular option is FETCH_OBJ
$output = $result->setFetchMode(PDO::FETCH_ASSOC);
// right here where we will brute force send the database data to the client.
// before we do that we need to format the data into a JSON data format:
echo json_encode($output);
}
catch (PDOException $e)
{
echo 'ERROR: Cannot retrieve data: ' . $e->getMessage();
}
?>
In the previous examples, a client sends a request to the server requesting some sort of information. The client only specify the table name and how many rows to return: { "table" : "customer", "limit" : 10 }.
That is a typical client/server or request/response interaction where the client only specify some sort of initiation to illicit some response from the server. In an API request/response model a client supplies some sort of authentication to get access to the remote server's API and once the remote server verified that the client is authentic, then the server will allow the client to access the server's API content.
For this example, you could send some sort of keys or password to the server instead of the table name and how many rows to return and have the server response with some sort of API content, i.e., a list of customer purchasing record stored on the remote server's database.
As you should know by now that responding to clients using JSON data structure is the most convenient way to process in a request/response model. So with that said, the JSON response from the server should looks something like this:
{
"id": "ch_1GWkp92eZvKYlo2CCjEC8ayY",
"object": "charge",
"amount": 100,
"amount_refunded": 0,
"application": null,
"application_fee": null,
"application_fee_amount": null,
"balance_transaction": "txn_19XJJ02eZvKYlo2ClwuJ1rbA",
"billing_detail":
{
"address":
{
"city": null,
"country": null,
"line1": null,
"line2": null,
"postal_code": null,
"state": null
},
"email": null,
"name": null,
"phone": null
},
"calculated_statement_descriptor": null,
"captured": false,
"created": 1586617247,
"currency": "usd",
"customer": null,
"description": "My First Test Charge (created for API docs)",
"disputed": false,
"failure_code": null,
"failure_message": null,
"fraud_detail": {},
"invoice": null,
"livemode": false,
"metadata":
{
"order_id": "6735"
},
"on_behalf_of": null,
"order": null,
"outcome": null,
"paid": true,
"payment_intent": null,
"payment_method": "card_1ApdgS2eZvKYlo2CfPJz8TrR",
"payment_method_detail":
{
"card":
{
"brand": "visa",
"check":
{
"address_line1_check": null,
"address_postal_code_check": null,
"cvc_check": null
},
"country": "US",
"exp_month": 6,
"exp_year": 2020,
"fingerprint": "Xt5EWLLDS7FJjR1c",
"funding": "credit",
"installment": null,
"last4": "4242",
"network": "visa",
"three_d_secure": null,
"wallet": null
},
"type": "card"
},
"receipt_email": null,
"receipt_number": null,
"receipt_url": "https://pay.example.com/receipt/acct_1032D82eZvKYlo2Ckp92e",
"refund":
{
"object": "list",
"data": [],
"has_more": false,
"url": "/v1/charge/ch_1GWkp92eZvKYlo2CCjEC8ayY/refund"
},
"review": null,
"shipping": null,
"source_transfer": null,
"statement_descriptor": null,
"statement_descriptor_suffix": null,
"status": "succeeded",
"transfer_data": null,
"transfer_group": null
}
That is of course a JSON data structure containing nested objects. How you access these nested objects is up to you. Hopefully, the examples shown thus far should give you some ideas on how to go about in accessing these nested objects.
Hint: make use of the dot "." notation object reference, i.e., myJSONObject.billing_detail.address.city, myJSONObject.billing_detail.address.state, myJSONObject.billing_detail.address.postal_code, myJSONObject.billing_detail.address.email, etc.
In the case of PHP, use "->" notation to access objects, i.e., $myJSONObject->billing_detail->address->city, $myJSONObject->billing_detail->address->state, $myJSONObject->billing_detail->address->postal_code, $myJSONObject->billing_detail->address->email, etc.
A JSON file looks just like any other JSON data structure, except it is in a file with the extension of .json. JSON files are typically being used in configuration schemes. For example, you could store your website configuration scheme in a JSON file or files instead of in the inline code.
Let's see what a JSON file looks like and how to parse it using PHP.
File: config.json.
{
"site":
{
"URL": "http:\/\/www.example.com\/",
"SECURE": "0",
"HASH": "8e60cfb",
"INSTALLATION": "0",
"THEME": "basic",
"PAGE": "admin",
"SESSION_EXPIRE": "1800",
"LOGO": "http:\/\/www.example.com\/image\/logo.jpg",
"FOOTER": "All rights reserved | email: contact@example.com"
},
"db":
{
"DB_NAME": "dashboard",
"HOST": "sharedhostingserver.com",
"USERNAME": "root123",
"PASSWORD": "pass12345"
},
"content":
{
"DOWNLOAD": "dashboard",
"ADMIN": "rule",
"EMPLOYEE": "rule123",
"SENOR_DISCOUNT": "15% OFF"
},
"sale":
{
"DISCOUNT": "60% OFF",
"DATE_EFFECTIVE": "May 1 to May 31",
"ITEM": ["All Nike Sneakers", "Men's Trousers", "Women's Skirts",
"T-shirts", "Handbags", "Shorts", "Sunglasses"],
"LAY-A-WAY": ["Luggages", "Men's Khaki", "Women's Bras", "Kids' pants"]
},
}
Okay, to parse this JSON file, we'll have to use PHP functions file_get_contents() along with json_decode() in combination. For example, suppose that you have a main application class (typically called main controller class in an MVC scheme of thing), and you want to set the properties from the configuration file similar to the one listed above, you can do like this:
<?php
public function init()
{
// read the configuration file assuming config.json is in the same
// directory as the main application file.
// or else, specify the exact directory path of the json file.
// for example showing only on the right side part:
// json_decode(file_get_contents('http://www.example.com/home/config/config.json'))
$config = json_decode(file_get_contents('config.json'));
// so here, it iterates through the JSON data structure in config.json
// with the first key being "site", 2nd key being 'db', 3rd is 'content', etc.
foreach ($config as $property => &$value)
{
$this->$property = &$value;
}
// now the foreach() loop is just for simple data structure like 'site' where
// you have no inner arrays or arrays of arrays like 'sale'.
// a better solution is to seperate your JSON data in several files, with one
// file handling the trivial data structure like 'site', 'db', 'content', etc.,
// and another handling the arrays of arrays like 'sale'.
// and then you can load each file and perform the setting of properties accordingly.
}
/**
* now once all the configuration have setted, you can access those properties like this:
*
* somewhere in other classes, you can use this main application class at will if
* you extend your class or classes from this main application class. for example:
*
* $obj = new MainApplication();
*
* this is for 'site':
*
* $url = $obj->site->URL;
* $hash = $obj->site->HASH;
* $theme = $obj->site->THEME;
* $cookie = $obj->site->SESSION_EXPIRE;
* $footer = $obj->site->FOOTER;
*
* and likewise, for 'db':
*
* $dbname = $obj->db->DB_NAME;
* $host = $obj->db->HOST;
* $username = $obj->db->USERNAME;
* $password = $obj->db->PASSWORD;
*
* and likewise, for 'content':
*
* $download = $obj->content->DOWNLOAD;
* $admin = $obj->content->ADMIN;
* $employee = $obj->content->EMPLOYEE;
* $senor_discount = $obj->content->SENOR_DISCOUNT;
*
* and likewise, for 'sale':
*
* $discount = $obj->sale->DISCOUNT;
* $sale_date = $obj->sale->DATE_EFFECTIVE;
*
* you might find a more elegant way of doing than what is shown here!
*
* $shoe = $obj->sale->ITEM[0]; // 'All Nike Sneakers'
* $pant = $obj->sale->ITEM[1]; // 'Men's Trousers'
* $skit = $obj->sale->ITEM[2]; // 'Women's Skirts'
* $t-shirt = $obj->sale->ITEM[3]; // 'T-shirts'
* $bag = $obj->sale->ITEM[4]; // 'Handbags'
* $short = $obj->sale->ITEM[5]; // 'Shorts'
* $sunglass = $obj->sale->ITEM[6]; // 'Sunglasses'
* $luggage = $obj->sale->LAY-A-WAY[0]; // 'Luggages'
* $khaki = $obj->sale->LAY-A-WAY[1]; // 'Men's Khaki'
* $bra = $obj->sale->LAY-A-WAY[2]; // 'Women's Bras'
* $kid_pant = $obj->sale->LAY-A-WAY[3]; // 'Kids' pants'
?>
Now to change the content of the file, you can do it like this:
<?php
// you can call this function accordingly
public function update()
{
// read the configuration file assuming config.json is in the same
// directory as the main application file.
// or else, specify the exact directory path of the json file.
// for example showing only on the right side part:
// json_decode(file_get_contents('http://www.example.com/home/config/config.json'))
$config = json_decode(file_get_contents('config.json'));
$config->site->THEME = 'advanced';
$config->site->INSTALLATION = '1';
$config->content->SENOR_DISCOUNT = '30% OFF';
$config->sale->DATE_EFFECTIVE = 'July 1 to July 31;
$config->sale->DISCOUNT = '60% OFF';
$config->db->DB_NAME = 'new_name_123';
$config->db->HOST = 'new_host_123';
$config->db->USERNAME = 'new_username_123';
$config->db->PASSWORD = 'new_pass_123';
// with all the new content have been prepared, we now can save them in the file
// the following statement will effectively replace the existing content with the
// newly prepared content above
file_put_contents('config.json', json_encode($config, JSON_PRETTY_PRINT));
}
// notice that only the items that are setted will take effect.
// the rest of the content in the file are unchange!
// JSON files are very useful in retrieving/adding/changing data on the fly!
?>
As you can see, it is very powerful using JSON file data structure to store and retrieve for any kind of purposes, however, using it as a configuration is probably the most useful for JSON files.
One last reminder about using JSON data structure is that it is not built for embedding comments in your JSON data structure; and therefore, comments in JSON data structure are to be avoided. However, you can still embedd your comments in your JSON data structure by using some hacks that people came up with. You'll have to search the Internet to find those hacks.
Before I dig into JSON files, let's clarify one issue that seems to get people confused, and that is, comments in a JSON data structure.
You can put comments on your JSON data structure, however, please be careful as JSON language is not meant to have a "dead" string language--meaning, a language that can ignore any string in data structure. JSON treats all strings as "live" data and parses them accordingly. Putting comments into your data structure can cause problems.
Think about it: if there are comments all over the JSON data structure, other languages would not be able to parse JSON data structure uniformly. JSON data structure is supposed to be language agnostic or neutral and if comments are put in the data structure, then how is one language suppose to differentiate and parse JSON data from another language?
This causes compatibility issue across languages that make use of the JSON data structure.
However, there are some hacks that people came up with for you to use to place comments in your JSON data structure. Here is one way of doing it:
Here is a hack found in the Google Firebase documentation that allows you to put comments in JSON:
{
"//": "Some browsers will use this to enable push notifications.",
"//": "It is the same for all projects, this is not your project's sender ID",
"gcm_sender_id": "1234567890"
}
Bottom line: Just to be on the safe side, don't use comments on your JSON data structure. If you need to, check out the Internet for more in dept discussions on this topic. I, personally, never use comments on my JSON data structure.
Section 11.6: Conclusion.
Paul S. Tuon
(Born: Cambodia)
`~The engine of your inginuity is limited only to your imagination!!!~`
Take what you need! ~~~
Give what you can!!!

UX Engineer
Minneapolis, MN (US)
Attended: University of
Minnesota (Twin Cities)
Majored: Economics/Computer
Science

Some Programming Knowledge:
Java, Delphi, C#, Python, PHP, Node.js, JavaScript, jQuery, Ajax, MySQL, PDO, and of course, CSS.
I enjoy programming and it feels like a hobby to me.
It probably falls in both categories of programming and hobbies!!!
See hobbies category below.
Social media:
Occationally (but not actively) love going online and interacting with total strangers on social medias!
Sports:
Occationally, enjoy watching/playing soccer, and the World Cup.
I was a long time avid season-ticket holder of the Minnesota United Prefessional Soccer Team prior to Covid-19.
Here is a soccer play that you'll never never NEVER NEVER going to see it happen again!!!
I repeat: never never NEVER NEVER going to see it happen again!!!
It has to be my favorite play in any sport.
Of course, I'm bias toward soccer, but still it is incredible and amazing, considering the scoring improbability of the game of soccer.
Here is the story:
Soccer player scores from 110 yards, possibly breaking world record
On Saturday March 18, 2023, a goalie for a Chilean soccer team may have set a new world record when he kicked from his own goal area -- a distance of about 110 yards -- that resulted in a goal.
Leandro Requena, goalkeeper for Cobresal in the Chilean Football Federation, took a goal kick (from his own goal area) during the team's game against Colo-Colo and the ball sailed into the opposing team's goal.
An amazing feat and hilarious as well.
"I wanted to take the kick quickly as we have done so many times at altitude, to try to catch the rival off guard and it came out a little stronger than normal," Requena told Radio Bio Bio.
Team officials estimated the goal was kicked from a distance of about 110 yards. The current Guinness World Record for longest goal in a competitive soccer match is 105 yards and was set by British player Tom King in January 2021.
"I asked Juan Silva, the club's manager, if the request for the record application was really going to be made and he told me, 'Obviously yes,'" Requena said.
For those of you who are not familiar with the game of soccer, you'll notice that the opposing goalie tried to use his head to knock the ball away from the direction of the goal area.
This is because he was out of the goal zone/area and he could not use his hands to touch the ball.
If he had used his hands to touch any part of the ball, it would have been a goal penalty kick, which sure would have been a goal.
The goal happened in the 77th minute of the (90 minutes + stoppage time) game tallying the score to 3 - 0 in favor of the Cobresal.
But toward the end of the game Colo-Colo scored a meaningless goal as time was about to run out, making the final score 3 - 1 with the Cobresal winning the game easily.
Here is the video of the March 21, 2023 play:
Soccer player breaking world record on a goal
Here is the video of the play of Tom King in January 2021:
Tom King breaks longest goal world record at 96.01m (105 yards)
Stoppage time: In soccer, extra playing time is added at the discretion of the referee after regulation play (of 90 minutes) has ended to compensate for stoppages in play caused by injuries, substitutions, or other interruptions.
Remember that in soccer, the regulation time is 90 minutes only, but the clock keeps running from the start to the finish (of the 90 minutes), even when a ball is out of bound or when the game is not being actively played. This is idle time or wasted time because the clock just keeps running from the start to the finish.
To compensate for those loss time, a stoppage time is added to the regulation time of 90 minutes -- hence, 90 minutes + stoppage time.
The stoppage time is usually about 4 to 8 minutes, depending on the flow of the game.
Okay, let's continue on the topic of (my) Hobbies:
Also, I enjoy horseracing (watching/betting -
and sometimes too much betting!!! --
way too much!!!).
Love the Triple Crown/Breeders Cup races. They're awesome and exciting!
After high school we went our seperate ways, or more specifically she went her seperate way when she decided to go to college out west, while I stayed put and attended the University of Minnesota right here in the Twin Cities.
We lost contact and never heard from each other ever since.
After college (University of Minnesota) we decided to go our seperate ways (amicably) and never heard from each other ever since.
PHNOM PENH: A NEW ERA HAS BEGUN AND THE HOPE AND EXCITEMENT IS IN THE AIR!
Go Phnom Penh Go!
Phnom Penh emerges on the scene as the only symbol of hope and excitement of carrying family banner to glory while at the same time trying to erase some of the disappointments left by his big sister Theravada.
***************
Side Note:
The horse name Cambodia, the dam of Theravada and Phnom Penh, was named by the U.S.-born and owners Don Robinson & Allan Schubert (both) of Kentucky.
The horse was named after the country of Cambodia.
The country name Cambodia was derived from the actual country name Kampuchea.
The country name Kampuchea (itself) was derived from an ancient Khmer folklore family clan Kambuja, who was the original king/leader of the ancient Khmer society.
Inside Cambodia it is being used by Cambodians as Kampuchea to this day, but outside of Cambodia it is being used mostly by non-Cambodians as Cambodia.
In the early 1800's, the Western World had difficulty pronouncing and spelling of the country Kampuchea, particularly when it came to the spelling of the people of Kampuchea.
Some outsiders (Western World) spelled it as Kampuchian and some spelled it as Kampuchean, so there was a lot of confusion.
So they decided to change/derive from Kampuchea to Cambodia instead and it was widely adopted by the rest of the world as the official country name ever since.
Now it is widely being known throughout the world as Cambodia, but inside Cambodia people still (today) use Kampuchea among themselves instead of Cambodia.
This phenomenon is not unique to Cambodia -- as a matter of fact -- it is very common for outsiders to give countries different names than its native names due to in part the difficulty in pronouncing and spelling of the native country names (a phenomenon known as exonym).
An exonym is a name given by outsiders to a person, group, language, or place, which differs from the name used by the local inhabitants (the endonym).
For example, "Germany" is the exonym for the country that is called "Deutschland" in its own language.
As similarly as with the people of Cambodia, the people of Germany to this day use "Deutschland" among themselves instead of Germany.
Other exonym phenomenon includes China which in its own Mandarin language is called Zhongguo; Japan which in its own language is called Nihon or Nippon; and Austria which in its own language is called Osterreich.
As for Theravada, she has a folklore [or an exonym] of her own -- though, through the meaning of her name.
Theravada means [in Khmer Language] "personal journey and enlightenment" ... to the religion of Buddhism; while Phnom Penh is the capitol city of Cambodia, and it means Superior Kingdom.
A name Phnom Penh was conceived during the heights of the Khmer Empire era to reflect the empire's dominance.
Personally, I am very grateful and thrilled that the owners of Cambodia, Theravada, and Phnom Penh decided to name their horses after Cambodia.
As a horse racing junkie, this is a dream any horse racing junkie would live for, and the fact that these people (Don Robinson & Allan Schubert) have the urge to name their horses after Cambodia, it shows that Cambodia must have touched their heart and soul in some form or another.
It is very refreshing for outsiders to name their horses after Cambodia, and I'm very grateful that Don Robinson & Allan Schubert (both) of Kentucky named their horses after Cambodia.
These people are not from Cambodia -- they're U.S.-born and raised in the middle of horse country (Kentucky) -- and for them to name their horses after Cambodia -- not once, not twice, but three times -- it says a lot about the character of these people.
As horse racing junkies would know -- this kind of thing usually happens only in dreams, but it is actually happening in real life, thanks to Don Robinson & Allan Schubert, IT IS HAPPENING IN REAL LIFE!!!
AND I'M THRILLED TO DEATH!
Now all I need is for them to name Theravada's and/or Cambodia's sons after Khmer Kings: Jayavarman I, Jayavarman II, Jayavarman III, Jayavarman IV, etc., similar to what we do here in the United States by naming sons after the father, i.e., Jones I, Jones II, Jones III, etc.
If they do that, I'll be going nuts!
Here's why:
In the early days of Khmer history, it was very chaotic where rival families or clans battled each other constantly to take control of the Kingdom.
If you know the history of Chinese dynasties, you know what I'm talking about -- they were constantly battling each other all the time.
The same thing was happening in the early days of the Khmer history -- they were constantly battling each other to take control of the Kingdom, and the majority of the reigns lasted only two years or less, but one particular Khmer King (if I remember Khmer history correctly), he set the record as the shortest reign of any Khmer Kings of only 18 days reigning as a king.
Short reigns were the norm in those days due to the constant battling of each other to take control of the Kingdom.
Rival families or clans would tried to overthrow the reigning king and take over the reign. It went on and on non-stop for decades and decades and decades and decades.
People were getting killed all the time due to the constant battling of each other.
One ordinary citizen, a middle age guy not related in blood to any prior kings/queens, decided that he had enough of the killings and the constant instability state of the kingdom, so he decided to take the matter into his own hands by forming a rival clan to overthrow the reigning king.
Forming a rival clan to overthrow the reigning king was not new in those days, and in fact, it was a regular occurrence in those days. But this middle age charismatic leader was different -- he was a visionary, and he had a vision that would set the foundation for the rise of the Khmer Empire.
People loved him, including ardent supporters of the reigning king.
He was a very charismatic leader who was able to garner the love and support from supporters of the rival reigning king.
It seemed like the tide was turning in favor of this charismatic leader, and now all he had to do was to go ahead and overthrow the reigning king by killing him and his family as well as the king's extended relatives to eliminate any future opposition.
He wiped them out completely and took over the reign quickly.
During his short reign, he preached unity, forgave supporters of former king by bringing them into his inner-circle, giving them jobs and other helpful necessities.
Throughout his reign, he preached stability of the kingdom, and rival would-be kings noticed the well-received message by the people.
In other words, the message that the new charismatic king preached was resonated with the people of that era and rival would-be kings took notice of that as well.
You'll see why that is so significant in a moment.
His main theme was the stability of the kingdom and the defending of the kingdom, and he called himself, not a king but, "Jayavarman I," meaning the first "protection or defense" of the kingdom.
Notice the use of the Roman Numerical order I, II, III, etc., equivalent to the first, the second, the third, etc.
So in Khmer literature, they referred to him as King Jayavarman the first, written as Jayavarman I.
People would referred to him not by his actual real name but by "Jayavarman I" and it resonated with the people of that era ever since.
Despite his popularity, he still had many ememies within the rowdy Khmer society, particularly loyalists to former king whom Jayavarman I got rid of.
Eighteen months later that visionary new king (Jayavarman I) was killed in the battlefield and his eldest son, believed to be only 19 or 20-year-old, took over the reign.
He heeded his father's advice and called himself Jayavarman II.
People responded to his call to follow his father's footsteps to "protection or defense" of the kingdom.
He lasted over seven years, if my memory of the Khmer history is correct, when he was killed in the battlefield trying to "protection or defense" of the kingdom.
His uncle, his father's older brother, took over the reign immediately after Jayavarman II was killed.
He, too, called himself Jayavarman III and people responded to his call to follow his brother's footsteps to "protection or defense" of the kingdom.
Sadly, because of his old age, his battlefield prowess was diminished greatly due to the fact that he was not able to join in the battlefield, and his leadership was somewhat not as strong as his younger brother or his 20-year-old nephew Jayavarman II.
His lack of leadership and other attributes may have angered "the-would-be" and "the wanted-to-be" kings, particularly future king to be Jayavarman IV, when Jayavarman IV turned against Jayavarman III soon thereafter the death of Jayavarman II.
As a top commander of the military under both Jayavarman I and Jayavarman II, future king to be Jayavarman IV fought along-side of the two kings during the battles, so definitely he did not harbor any ill-will toward the two former kings.
However, he may have had resentment toward the third member of that family, Jayavarman III, for taking over the reign; and perhaps due to jealousy, he may have viewed him as unqualified or unfit or not deserved to be king.
I'm not well-versed in Khmer history, but I think that it was his ambitions to be king that created the animosity toward Jayavarman III, and the fact that he, being future king to be Jayavarman IV, may have viewed Jayavarman III as unqualified or unfit or not deserved to be king that fueled his hostility toward Jayavarman III. [That is just my opinion!]
Future king to be (Jayavarman IV) had the will and the means to achieve his ambitions due to the fact that he was the top military commander under all three of the kings, including under Jayavarman III.
Personally, I think he may have had some disagreements with Jayavarman III, or he may have had ambitions of his own to be king, but whatever the reason, he quickly turned against Jayavarman III.
He definitely didn't like Jayavarman III, but he did like the other two kings: Jayavarman I, Jayavarman II.
After a military coup [to use today's term] future king to be (Jayavarman IV) took the time and effort to honor all three of them, despite savagely killing one of them, Jayavarman III.
He even took the name Jayavarman IV (the fourth) as his reigning king name [in honor of all three of his adversaries.]
Early on before he decided to overthrow the reigning king [in a military-style coup -- to use today's term] he knew that he needed the support of everybody, including loyalists to the reigning king, and that's why he ordered to spare the lives of the reigning king's immediate family and relatives, because he knew he needed unity and he needed to defuse the anger that may have come from ardent supporters of Jayavarman III that may have arisen after savagely killing Jayavarman III.
He tried very hard to justify his actions and tried to convince people that he was not an evil man, and it may have worked as people seemed to listen what he had to say and believed him.
He went to extra lengths to honor his former adversaries, two of them, Jayavarman I and Jayavarman II, he had nothing to do that caused them being killed.
From that era and on, all subsequent Khmer Kings took the name of Jayavarman as the prefix name and followed by the Roman Numerical number order (i.e., Jayavarman V, Jayavarman VI, Jayavarman VII, Jayavarman VIII, etc.) as their reigning king name.
To make a long story short, those four Khmer Kings set the foundation for the rise of the Khmer Empire, in which, each subsequent Khmer King tried to outdo the one prior, fueling a competitive spirit that gave rise to the building of an empire, the Khmer Empire, as well as resulted in the building of the Ankor Wat, plus hundreds and hundreds of other monuments that scattered throughout Southeast Asia [to this day].
That competitive spirit was the sort of thing that, "If you can do that I can do better" mentality, and it went on and on and on like a ritual.
What the remarkable thing about it, is that subsequent kings after Jayavarman IV chose to honor their predecessors and not even trying to make a name for themselves, like calling themselves in some other names to establish an identity of their own instead of adopting the name of Jayavarman.
You would think that they would have lots of egos and wanted their own identity to be in the history books, but contrary to what we believe, they had none of the egos. [Incredible!]
[Side note: I referred to Jayavarman I, Jayavarman II, Jayavarman III, Jayavarman IV for clarity and convenient purposes only as I'm not well-versed in Khmer history. It could actually be Jayavarman X, Jayavarman XI, Jayavarman XII, Jayavarman XIII, or later group of four consecutive kings, but the sequence of events, I believe to be correct.]
Anyhow, come to think of it, those Khmer Kings would be rolling their bodies in their graves with their face downward in shame after seeing how Donald Trump behaves toward his predecessors, particularly Joe Biden.
Anyhow [politic aside], if Don Robinson & Allan Schubert name Cambodia's and Theravada's sons after these Khmer Kings in the future, I'M GOING NUTS!!!
I DON'T THINK I'LL BE ABLE TO CONTAIN MYSELF FROM EXCITMENT!
***************
Using his big sister Theravada's "personal journey and enlightenment" as a metaphor, the 'journey' ahead for Phnom Penh is full of anticipation and excitement, starting Thursday October 2, 2025, when Phnom Penh is scheduled to run in the 1 1/16 Miles | Open | 2 Year Olds | MAIDEN SPECIAL WEIGHT | PURSE: $85,000, running in the 4th race at Aqueduct against 10 other good group of two-year-olds.
Looking at the field a lot of these two-year-olds are well-bred horses, one particular horse of interest is a colt trained by Chad Brown and he is named Special Envoy (by Not This Time - Stillwater Cove, by Quality Road).
Special Envoy (ML 5-2 favorite) is a $1,000,000 yearling purchase and he is owned by Peter M. Brant, Mrs. John Magnier, Michael B. Tabor, Brook T. Smith, Derrick Smith.
Special Envoy has been on my "Stable Watch Two-Year-Old" for quite some time and he has been working steadily since May 2025, but his first published workout was on July 8, 2025, working 3f in 39.52 (b) ... 22/23.
Here are the rest of his workouts:
Special Envoy workouts at Belmont Park
4f, Sep 27th, in 49.42 (b) ... 74/213
4f, Sep 21st, in 49.81 (b) ... 53/119
4f, Sep 14th, in 50.23 (b) ... 82/113
4f, Sep 6th, in 48.50 (bg) ... 26/211
4f, Aug 30th, in 49.49 (b) ... 24/79
4f, Aug 23rd, in 49.95 (b) ... 62/106
4f, Aug 16th, in 49.49 (b) ... 26/104
4f, Aug 9th, in 49.77 (bg) ... 19/76
4f, Aug 3rd, in 49.66 (b) ... 17/58
4f, July 27th, in 50.52 (b) ... 36/53
3f, July 21st, in 37.75 (b) ... 5/9
3f, July 8th, in 39.52 (b) ... 22/23
That is twelve workouts!
Special Envoy's dam, Stillwater Cove, is a 9-year-old mare that was born in 2016 and raced from 2018 to 2020. She was trained by Wesley A. Ward.
Stillwater Cove has raced at Ascot Racecourse, Belmont Park, Churchill Downs, Del Mar, Keeneland, Kentucky Downs, Saratoga, Turfway Park, Woodbine with wins at Keeneland, Saratoga. Her lone stakes win was at Saratoga in the 5 1/2-furlong overnight Bolton Landing Stakes (on Turf) in 2018.
Stillwater Cove competed in nine stakes races, mostly on turf, but the best she could have done [beside the Bolton Landing Stakes win] was a second-place in the 5 1/2-furlong (Turf) overnight Limestone Stakes at Keeneland in 2019; a fourth-place in the 7f-turf Soaring Softly Stakes (Gr 3) at Belmont Park in 2019; a fourth-place in the 6 1/2f-turf Ladies Turf Sprint (Gr 3) at Kentucky Downs in 2019.
As you can see, they purchased Special Envoy for $1,000,000 as yearling for a reason -- he is a well-bred horse whose dam is also a well-bred horse with excellent race record.
Special Envoy is the 5-2 morning line favorite and the one to beat.
Senor Lender, also trained by Chad Brown, is the 7-2 morning line second choice. [But personally, he is not appealed to my liking. So I will stay away from him.]
Another horse that piqued my interest is Epic Desire (by Uncle Mo - Brooklynsway, by Giant Gizmo) trained by Todd A. Pletcher.
Epic Desire is the 5-1 morning line fourth choice.
Epic Desire has raced three times thus far, making his debut in mid-April 2025 at Keeneland in a 4 1/2f-dirt maiden special weight race where he finished 6th; his next race was in mid-July 2025 at Saratoga in a 7f-dirt maiden special weight race where he finished 2nd; his last race was in mid-August 2025 at Saratoga in a 1 1/16 miles-turf maiden special weight race where he finished fourth.
Epic Desire is a homebred and owned by his breeder. He is a Full brother to Adare Manor.
Looking at Epic Desire's dam, Brooklynsway, she has a stellar race record with a most notable win in the 1 1/16 miles-dirt Doubledogdare Stakes (G3) at Keeneland in April 2016; a second-place in the 1 1/18 miles-dirt Fleur de Lis (Gr 2) at Churchill Downs in June 2016.
She competed in all stakes races, albeit mostly overnight stakes, during her racing career while competing at Arlington Park, Churchill Downs, Ellis Park, Fair Grounds, Horseshoe Indianapolis, Keeneland, Prairie Meadows, Woodbine.
To top it all off, she produced Adare Manor.
Another horse of interest is Oban (by Constitution - Joyful Addiction, by Munnings) also trained by Todd A. Pletcher.
Oban is the 6-1 morning line fifth choice.
Oban's dam, Joyful Addiction, is an unraced 7-years-old mare who experienced soundness issue that prevented her from racing.
Sounds like Theravada, to me! But Theravada made it to the racetracks four times.
According to my research, it says:
"Retired due to physical problems," according to the horse owners MyRaceHorse Stable. "The diagnostics revealed fragmental fractures in Joyful Addiction's left knee. While surgery is possible, the underlying bone disease is a concern for future soundness and racing," noted by MyRaceHorse Stable in a Press Release.
Oban is a $500,000 yearling purchase and he is unraced thus far, but judging by his workouts pattern, he is a huge contender in this race.
Here are his workouts:
Oban workouts at Saratoga
4f, Sep 22nd, in 50.55 (b) ... 22/41
4f, Sep 15th, in 51.82 (b) ... 39/47
4f, Aug 31st, in 49.66 (b) ... 31/53
4f, Aug 24th, in 48.63 (bg) ... 15/112
4f, Aug 18th, in 50.88 (b) ... 27/29
4f, Aug 11th, in 49.56 (b) ... 12/28
4f, Aug 5th, in 49.54 (b) ... 24/38
4f, July 29th, in 51.33 (b) ... 49/62
4f, July 21st, in 49.44 (b) ... 22/44
4f, July 14th, in 48.88 (b) ... 34/95
4f, July 6th, in 48.88 (b) ... 34/132
3f, June 28th, in 38.58 (b) ... 6/12
3f, June 21st, in 38.23 (b) ... 3/11
Another interesting horse is Behold the King (by Not This Time - Behold The Queen, by Animal Kingdom) trained by Mark Casse.
Behold the King is the 4-1 morning line third choice.
Behold the King is a $175,000 yearling purchase and he has raced three times thus far; he finished 2nd on his debut in a 1 mile-turf maiden special weight race at Colonial Downs in July 2025; he finished 2nd in a 1 mile-turf maiden special weight race at Colonial Downs in August 2025; he finished 2nd in a 1 1/16 miles-turf maiden special weight race at Colonial Downs in mid-September 2025.
Behold the King is definitely a contender in this race.
Another interesting horse is Chambersville (by Twirling Candy - Reef Point, by Giant's Causeway) trained by Kenneth G. McPeek.
Chambersville is a $275,000 (RNA) at the yearling auction and he has raced once thus far, finishing 7th on his debut in a 1 1/16 miles-turf maiden special weight race at Saratoga in August 2025.
His dam, Reef Point, has raced only once in her racing career and it was in October 2015 in a 1 1/16 miles-turf maiden special weight race at Belmont Park where she finished 9th of twelve.
She was injured after that race and she was retired to broodmare the following breeding season (January and February 2016).
Sounds like Theravada, to me!
As for Phnom Penh, he is a 15-1 longshot and he will break from post position 4.
Phnom Penh is facing a stellar group of 2yos but I'm not discouraged at all, and I think it will serve him well into the future if he's going to carry his family banner to glory.
ENJOY THE RACE EVERYBODY!
UPDATE: October 2, 2025
Result:
1. Behold the King 6-1 (third-choice)
2. Chambersville 2-1 (second-choice)
3. Epic Desire 12-1
4. Fleet N Readt 45-1
The 6-5 favorite Special Envoy finished a distance sixth, beaten 9 lengths.
Phnom Penh 29-1 finished nineth, beaten 18-20 lengths.
Phnom Penh, as usual, was off evenly among the three slowest out of the gate due to a lack of gate speed.
The trio continued to race almost as a team at the rear for much of the race and never seemed to gain any ground on any horse in front of them.
As for Phnom Penh, he tried to move up mildly on the far turn but flatten out turning for home to finish 9th, beaten 18-20 lengths.
The race itself was very slow, time wise, compared to a race that was run one hour earlier that has identical condition and distance but with a much weaker group of 2yos. [23.56, 48.77, 1:13.42, 1:37.00, 1.42.93]
This race that Phnom Penh was in contained a stellar group of 2yos but the fractions and final times were slower than the times of the much weaker group of 2yos -- go figure that out. [23.64, 48.72, 1:14.07, 1:37.92, 1:44.05]
That is more than one seconds slower than the much weaker group of 2yos. [Go figure that out!]
As for Phnom Penh -- on to the next race in the near future as he is physically sound after seeing his race.
A side note:
A shout out to Belmont at the BigA racing analyst Greg Wolf for picking Phnom Penh (29-1) to win the race but he ran to his odd.
So I'm not alone in picking and playing Phnom Penh to win in this race.
During the paddock preview, when they showed the analyst picks on the TV screen, people at the racetrack where I was were chastising Greg Wolf for picking the longest-odd horse in the field.
I don't blame them for chastising Greg Wolf but that doesn't mean that Greg Wolf is a bad horse racing analyst. He just happened to like Phnom Penh better than other horses in this race.
So keep your head up high, Greg!
Other note regarding Don Robinson, one of the owners of Cambodia, Theravada, and Phnom Penh:
Winter Quarter Farm in Lexington, KY is owned and operated by Don Robinson, a fourth-generation horseman who has raised many top racehorses at the farm.
The 276-acre operation has been in Robinson's family for generations.
History:
The farm has been in the same family for four generations, with Don Robinson's father also boarding excellent runners there.
Farm Type:
A Thoroughbred operation that focuses on breeding and raising racehorses.
Notable Achievements:
Winter Quarter Farm has raised top horses like Golden Pheasant and Star of Cozzene.
THE DEVASTATING DISAPPOINTMENT OF SENTIMENTAL FAVORITE THERAVADA IS STILL FRESH AND NOT GOING AWAY ANY TIME SOON EITHER!
AMIDST ON-GOING DEVASTATING DISAPPOINTMENT AND UNFULFILLED HIGH EXPECTATIONS OF THERAVADA A NEW HOPE AND EXCITEMENT EMERGED!
I am still not getting over the devastating disappointment and unfulfilled of high hope and expectations of sentimental favorite Theravada for not being able to continue her journey as a race horse and it puts a dampen on my spirit as a horse racing junkie.
She had so much promise and potential after her 2nd race and my spirit as a horse racing junkie was sky-high after seeing her new dimension in her racing style that deviates from her mom's deep closing running style.
As any horse racing fan knows a big and tall horse with abundance of speed and stamina is a horse to be reckon with in horse racing paradym -- and Theravada is one of those horses who has that trait.
It's too bad that her soundness prevents her from utilizing that trait to the fullest extent to fulfill high hope and expectations.
I still can't believe it -- it's just too bad that things had to happen that way.
Oh, well, maybe it never meant to be!
".... A NEW HOPE AND EXCITEMENT EMERGE!"
On Saturday September 13, 2025, a new generation of hope and pent-up excitement emerged on the scene to carry on the hope and excitement while at the same time kind of erasing some of the devastating disappointment created by Theravada.
That new generation of hope and pent-up excitement surrounded Theravada's two-year-old half-brother named Phnom Penh who is by Medaglia d'Oro out of a War Front mare Cambodia.
Yes, Theravada has a little brother, a two-year-old, running in the 4th race at Aqueduct on Saturday September 13, 2025, in a six-furlong maiden special weight race on the grass against nine tough group of two-year-olds.
YAY!!!
Let's hope Phnom Penh can carry on the family banner to glory, erasing Theravada's unfulfilled high hope and expectations.
I'm thrilled to see Phnom Penh emerges on the scene and he couldn't come soon enough for my sake.
BUT HE IS HERE -- AND I'M THRILLED TO DEATH!
Phnom Penh, like his older sister Theravada, is a Kentucky home-bred of Don Robinson & Allen Schubert, but he is trained by Tom Proctor.
Phnom Penh finished 9th (and next to last -- not very encouraging), beaten 12 lengths.
However, I'm not the least disappointed nor discouraged because of the fact that he is a two-year-old just starting his racing career.
He has a future ahead of him and I'm looking forward to his many, many races in the future.
As for his sister Theravada -- she didn't start her racing career until she was three-year-old; perhaps due to soundness issue that prevented her from racing as a two-year-old.
To see Phnom Penh starts his racing career as a two-year-old it gives me a lot of hope and excitement and not to mention an anticipation for good things to come from him.
Phnom Penh was off evenly in midpack, which is his mom's typical running style, and he continued to race in midpack to the half-mile marker when he tried to move up 3- or 4-wide due to the inside there were a bunch of horses so the jockey had to go wide but a chain reaction from the horses to his inside who drifted outward causing Phnom Penh to steady significantly while losing more grounds to the leaders.
Phnom Penh continued wide on the far turn, about 5-wide at the quarter-pole, and continued to be very wide turning for home, and ran evenly in the stretch and never felt a whip from his jockey [due to the jockey realizing in futility to ask the horse for his best.]
The even-money favorite, trained by Brad Cox, is Abrigado who finished 5th, beaten 5 1/2 lengths; the 5/2 2nd choice No Pressure finished 2nd, beaten 1/2 length; while the winner is a 9-1 choice Expressway, trained by Bill Mott.
Phnom Penh was sent off as one of the longshots at 20-1 and he ran like it.
To be honest, I'm not disappointed in any shape or form, all things considered.
Actually, I'm thrilled just to see him show up in a race after what happened with Theravada.
So I'm looking forward to Phnom Penh's next race in the near future.
IS IT GREAT TO BE A HORSE RACING JUNKIE or what?
FIFA World Cup takes place every four year and is being played in the summer usually in the months of June and July.
The 2026 World Cup is scheduled to take place from June 8 through July 3 (2026).
Going forward FIFA World Cup had agreed that the number of games for the 2026 World Cup (and beyond) would increase and the format would change from the previous format of 16 groups of three teams to 12 groups of four teams.
So there will be 12 groups of four teams starting in the 2026 World Cup and beyond.
The new format will have 104 games played, up from the original 80.
The tournament starts off with each group plays each other in the group for three games each.
The point standings are determined from each game played with a win receiving 3 points, a tie receiving 1 point, and a loss receiving 0 point.
After each team played each other in the group three games, the final point standing in the group is determined.
The top two teams from each group will go through (or advanced to the next round), with the eight best third-place teams also advancing to the Round of 32.
The key phrase is "... eight best third-place teams ...."
In other words, eight best teams from the 12 groups whose records are not the top two from each group will also be advancing to the Round of 32.
This means that there are 32 teams [(12 x 2) plus 8] will advance to the next round -- the Round of 32.
The 2026 World Cup will take place in three North American countries: the United States, Mexico, and Canada.
Yes, that is right: three countries are set to host the 2026 World Cup.
This will be the first time that the tournament is hosted by three different nations and it will be the very first time that the event will be contested in Canada.
There will be a total of 16 venues used as host cities for the 2026 World Cup. The U.S. will have 11, Canada will have 2, and Mexico will have 3.
As stated earlier, starting in the 2026 World Cup there will be an expanded format featuring 48 teams split into 12 groups of 4 -- as opposed to prior format when there were also 48 (16 X 3) teams but were instead split into 16 groups of 3.
2026 World Cup host cities:
USA: 11
Atlanta: Mercedes-Benz Stadium
Boston: Gillette Stadium
Dallas: AT&T Stadium
Houston: NRG Stadium
Kansas City: Arrowhead Stadium
Los Angeles: SoFi Stadium
Miami: Hard Rock Stadium
New York/New Jersey: MetLife Stadium
Philadelphia: Lincoln Financial Field
San Francisco:Levi's Stadium
Seattle: Lumen Field
Wait a minute: Houston, Kansas City, and San Francisco?
What happen to the northern upper midwest cities like Cleveland, Detroit, Chicago, Minneapolis and Denver?
It would have been a great idea to leave out Houston, Kansas City, and San Francisco and put in the northern upper midwest cities like Cleveland, Detroit, Chicago, Minneapolis and Denver.
So take out Houston, Kansas City, and San Francisco and put in Chicago, Minneapolis, and Denver.
That would be great and I will camp out for the tickets (for sure).
Canada: 2
Toronto: BMO Field
Vancouver: BC Place
Mexico: 3
Guadalajara: Estadio Akron
Mexico City: Estadio Azteca
Monterrey: Estadio BBVA
The four teams in each group will compete against each other in the round-robin group stage, and the standings are based on points gained from those matches.
Depending on the result of each group stage game, teams earn a certain number of points (3 points for a win, 1 point for a draw, 0 points for a loss).
After each team has played all three group stage matches, the two teams with the most points in each group will advance to the knockout rounds (beginning in round of 32), while the bottom two are eliminated..
If two or more teams are tied on the same number of points, a series of tiebreakers are used to determine which team will finish above the other(s) in the table.
If two or more teams are tied on the same number of points following the group stage, tiebreakers are first based on goal differential, which is a team's total goals scored minus their goals conceded.
If they are still tied, goals scored will determine who moves on.
If teams are still tied, head-to-head records will be used to decide which side progresses.
In the knockout stage (round 32), if two teams are tied after 90 minutes, two extra 15-minute periods are played. If the two teams are still tied, penalty kicks will be taken to determine the winner.
After the group stage, the tournament moves into the round of 32. From there, eight teams will compete in the quarterfinals, four in the semifinals and two in the final to crown a champion.
The runners-up of the semifinals will compete to determine the third-place winner.
FIFA Women's World Cup takes place every four year and is being played in the summer usually in the months of July and August.
The FIFA Women's World Cup will have a format featuring 32 (8 X 4) teams split into 8 groups of 4 team.
The 2023 FIFA Women's World Cup is scheduled to take place from July 20 through August 20 (2023).
Soccer (or Football) fans (as of this writing May 1, 2023) are counting down the days as Australia and New Zealand are set to become the first countries in the Southern Hemisphere to host the FIFA Women's World Cup.
Yes, you heard it right two countries: Australia and New Zealand.
This will be the first time that the tournament is hosted by two different nations.
The 2023 FIFA Women's World Cup is set to be held in the Oceanic regions of Australia and New Zealand, the competition will run from July 20, 2023 through to the final exactly a month later on August 20, 2023.
The first match will take place in New Zealand with Norway vs New Zealand on July 20, 2023.
The 2023 Women's World Cup tournament fever is most definitely kicking in as the opening kick approaches and fans couldn't be more excited.
As per reports, Organizers say they are on course to sell a record 1.5 million tickets.
Currently world champions USA find themselves in Group E along with the Netherlands, Portugal and Vietnam, while European champions England are in Group D alongside China, Denmark and Haiti.
The USA better watch out for the Netherlands, their main threat to upset in the group stage. The Netherlands is a very good team coming out of Group E.
The intercontinental qualification play-offs finished on 23 February 2023, and therefore all spaces in the final competition have now been finalized - with Haiti, Portugal and Panama securing the last three spots.
With all teams now confirmed, here are the finalized groups and schedule for the 2023 FIFA Women's World Cup.
New Zealand
Norway
Philippines
Switzerland
Australia
Canada
Nigeria
Republic of Ireland
Costa Rica
Japan
Spain
Zambia
China
Denmark
England
Haiti
Netherlands
Portugal
United States
Vietnam
Brazil
France
Jamaica
Panama
Argentina
Italy
South Africa
Sweden
Colombia
Germany
South Korea
Morocco
Group A: Jul 20, 2023
New Zealand v Norway
Group A: Jul 21, 2023
Philippines v Switzerland
Group B: Jul 20, 2023
Australia v Republic of Ireland
Group B: Jul 20, 2023
Nigeria v Canada
Group C: Jul 21, 2023
Spain v Costa Rica
Group C: Jul 22, 2023
Zambia v Japan
Group D: Jul 22, 2023
England v Haiti
Group D: Jul 22, 2023
Denmark v China
Group E: Jul 22, 2023
United States v Vietnam
Group E: Jul 23, 2023
Netherlands v Portugal
Group F: Jul 23, 2023
France v Jamaica
Group F: Jul 24, 2023
Brazil v Panama
Group G: Jul 23, 2023
Sweden v South Africa
Group G: Jul 24, 2023
Italy v Argentina
Group H: Jul 24, 2023
Germany v Morocco
Group H: Jul 25, 2023
Colombia v South Korea
Group A: 25 Jul, 2023
New Zealand v Philippines
Group A: 25 Jul, 2023
Switzerland v Norway
Group B: 26 Jul, 2023
Canada v Republic of Ireland
Group B: 27 Jul, 2023
Australia v Nigeria
Group C: 26 Jul, 2023
Spain v Zambia
Group C: 26 Jul, 2023
Japan v Costa Rica
Group D: 28 Jul, 2023
England v Denmark
Group D: 28 Jul, 2023
China v Haiti
Group E: 27 Jul, 2023
USA v Netherlands
Group E: 27 Jul, 2023
Portugal v Vietnam
Group G: 28 Jul, 2023
Argentina v South Africa
Group G: 29 Jul, 2023
Sweden v Italy
Group F: 29 Jul, 2023
France v Brazil
Group F: 29 Jul, 2023
Panama v Jamaica
Group H: 30 Jul, 2023
Germany v Colombia
Group H: 30 Jul, 2023
South Korea v Morocco
Group A: 30 July, 2023
Norway v Philippines
Group A: 30 July, 2023
Switzerland v New Zealand
Group B: 31 July, 2023
Canada v Australia
Group B: 31 July, 2023
Republic of Ireland v Nigeria
Group C: 31 July, 2023
Japan v Spain
Group C: 31 July, 2023
Costa Rica v Zambia
Group D: 1 Aug, 2023
Haiti v Denmark
Group D: 1 Aug, 2023
China v England
Group E: 1 Aug 3:00pm ET (double check time)
Portugal v USA
Group E: 1 Aug, 2023
Vietnam v Netherlands
Group F: 2 Aug, 2023
Panama v France
Group F: 2 Aug, 2023
Jamaica v Brazil
Group G: 2 Aug, 2023
Africa v Italy
Group G: 2 Aug, 2023
Argentina v Sweden
Group H: 3 Aug, 2023
South Korea v Germany
Group H: 3 Aug, 2023
Morocco v Colombia
At this stage the group competion is completed and from here and on winner advances, loser goes home.
During the group competion, each team in the group play each other and earns points based on win or draw.
Depending on the result of each group stage game, teams earn a certain number of points (3 points for a win, 1 point for a draw, 0 points for a loss).
After each team has played all three group stage matches, the two teams with the most points in each group will advance to the knockout rounds (beginning in round of 16), while the bottom two are eliminated.
If two or more teams are tied on the same number of points, a series of tiebreakers are used to determine which team will finish above the other(s) in the table.
If two or more teams are tied on the same number of points following the group stage, the below criteria are used, in this order, to determine the rankings of those teams in their group:
1. Superior goal difference in all group matches
2. Greatest number of goals scored in all group matches
3. Greatest number of points obtained in the group matches between the teams concerned
4. Superior goal difference resulting from the group matches between the teams concerned
5. Greatest number of goals scored in all group matches between the teams concerned
6.Highest team conduct score relating to the number of yellow and red cards obtained***
7. Drawing of lots
***For tiebreaker #6 above (highest team conduct score), the team with the highest number of points after the group stage, based on the below criteria, shall be ranked highest:
Yellow card: minus 1 point
* Indirect red card (two yellows): minus 3 points. [An indirect red card is the result of two yellow cards and is equivalent to one red card.]
* Direct red card: minus 4 points
* Yellow card and direct red card: minus 5 points
(win advance, lose go home)
Group A: 5 Aug, 2023
Group A Winner v Group C Runner-up
Group B: 7 Aug, 2023
Group B Winner v Group D Runner-up
Group C: 5 Aug, 2023
Group C Winner v Group A Runner-up
Group D: 7 Aug, 2023
Group D Winner v Group B Runner-up
Group E: 6 Aug, 2023
Group E Winner v Group G Runner-up
Group F: 8 Aug, 2023
(8 winners of round 16 advance)
Aug 10 - 12, 2023
The 8 teams remaining will pair up to eliminate each other (win advance, lose go home).
Aug 15 - 16, 2023
The 4 teams remaining will pair up to eliminate each other.
The winners of each semi-final will face off in the FIFA Women's World Cup final on Sunday August 20, 2023 at Stadium Australia, Sydney.
The runners-up of each semi-final will play each other the day before on Saturday August 19, 2023, in Brisbane Stadium to battle it out for third place.
Where to watch FIFA Women's World Cup 2023?
In the USA, Fox will be airing all games on its main channel as well as Fox Sports.
The FIFA U-20 World Cup is the biennial (every two years) football (soccer) world championship tournament for FIFA members’ men's national teams with players under the age of 20; hence, the U-20.
Argentina have been selected to host the 2023 FIFA Under-20 World Cup.
The tournament is to take place between May 20 and June 11 (2023) in Argentina.
The FIFA U-20 World Cup 2023 consists of six groups: A, B, C, D, E, and F.
The top two teams from each of the six groups will advance to the last 16 (or Round 16), as well as the four best third-placed teams.
Let's do the math: 16 teams (6 groups multiply by top 2 teams plus 4 third-placed teams) will advance to the last 16 (or Round 16).
That is a total of 16 teams that will advance to the knockout round.
But first, here are the six groups:
Argentina
Uzbekistan
Guatemala
New Zealand
USA
Ecuador
Fiji
Slovakia
Senegal
Japan
Israel
Columbia
Italy
Brazil
Nigeria
Dominican Republic
Uruguay
Iraq
England
Tunisia
France
Korea Republic
Gambia
Honduras
Each team plays each other in the group three times to determine the top two in the standing.
The top two teams in the group will advance to the next round, which is round 16.
Saturday, 20 May:
Group A: Argentina vs Uzebistan
Group A: Guatemala vs New Zealand
Group B: United States vs Ecuador
Group B: Fiji vs Slovakia
Sunday, 21 May:
Group C: Senegal vs Japan
Group C: Israel vs Colombia
Group D: Italy vs Brazil
Group D: Nigeria vs Dominican Republic
Monday, 22 May:
Group E: Uruguay vs Iraq
Group E: England vs Tunisia
Group F: France vs Republic of Korea
Group F: Gambia vs Honduras
Tuesday, 23 May:
Group A: Argentina vs Guatemala
Group A: New Zealand vs Uzbekistan
Group B: United States vs Fiji
Group B: Slovakia vs Ecuador
Wednesday, 24 May:
Group C: Senegal vs Israel
Group C: Colombia vs Japan
Group D: Italy vs Nigeria
Group D: Dominican Republic vs Brazil
Thursday, 25 May:
Group E: Uruguay vs England
Group E: Tunisia vs Iraq
Group F: France vs Gambia
Group F: Honduras vs Republic of Korea
Friday, 26 May 2023:
Group A: New Zealand vs Argentina
Group A: Uzbekistan vs Guatemala
Group B: Slovakia vs United States
Group B: Ecuador vs Fiji
Saturday, 27 May:
Group C: Colombia vs Senegal
Group C: Japan vs Israel
Group D: Dominican Republic vs Italy
Group D: Brazil vs Nigeria
Sunday, 28 May:
Group E: Tunisia vs Uruguay
Group E: Iraq vs England
Group F: Honduras vs France
Group F: Republic of Korea vs Gambia
After the group stage the knockout stages begin in the round of 16 and continues to the final.
In the knockout stages in any match a winner advances, loser goes home.
30 May - 1 June: Round of 16
3 - 4 June: Quarter-finals
8 June: Semi-finals
11 June: FIFA U-20 World Cup 2023 Final
The FIFA U-20 Women's World Cup is a biennial event (or takes place every two years) for women's national teams with players under the age of 20.
Costa Rica hosted the 2022 FIFA Under-20 (Young Women's) World Cup, in which, Spain had won the Cup.
The next FIFA U-20 Women's World Cup event will take place in 2024.
Major League Soccer is a men's professional soccer league sanctioned by the United States Soccer Federation, which represents the sport's highest level in the United States.
The league comprises 29 teams -- 26 in the U.S. and 3 in Canada.
MLS is currently at 29 teams with the league aiming to reach 30 teams through expansion with bids from Las Vegas, San Diego, and Phoenix under consideration.
The league is headquartered in Midtown Manhattan (New York).
The MLS is divided into two conferences:
The Western Conference and the Eastern Conference.
Note: Some teams have "FC" attached to their names -- with "FC" stands for Football Club -- with "F" an apparent link to a soccer term known throughout the world: Football.
However, Miami's soccer team is called Inter Miami CF and not Inter Miami FC.
Make note of the placing of the letters: "CF" -- not "FC".
But why?
The name derives and originates from South America and it was called Club Internacional de Futbol Miami (in Spanish South America).
However, in North America it is known as Inter Miami CF or simply Inter Miami -- an American professional soccer club based in the Miami metropolitan area.
Likewise, the Montreal soccer team has a "CF" attached to its name as well.
The club's name is Club de Foot Montreal (in French) -- hence, "CF".
On the other hand, the Nashville, the Orlando City, and the St. Louis City soccer teams have an "SC" attached to their names.
The "SC" stands for Soccer Club.
The Eastern Conference
Note: New York has two teams.
The Western Conference
Note: LA has two teams.
For 2023 season, MLS teams play 34-match regular season from February to October with 18 of the 29 clubs (the top nine from each of the Eastern and Western conference) advancing to the playoffs at season's end.
Beyond 2023, MLS teams probably will still play 34-match regular season (as well) from February to October. [Please stay tuned.]
How many games does each team play?
Each season every team plays 17 games at home and 17 away, for a total of 34 regular season games.
All teams play everyone in their respective Conference twice - one at home and one away - and an additional eight matches against teams in the other Conference.
This is similar to an NFL season where all teams play everyone in their respective Division twice - one at home and one away - and play some additional games against teams in other Conference/Divisions.
The team that accrues the most regular season points across both Conferences is awarded the Supporters Shield, and the best performers progress to MLS Cup Playoffs...
How do points standings are calculated?
Each team play 34 games in a season and earns points based on win or draw.
Depending on the result of each game, teams earn a certain number of points (3 points for a win, 1 point for a draw, 0 points for a loss).
Throughtout the season (from start to finish), team standing is calculated based on points earned (and tallied/totalled) after each game played.
In other words, throughtout the season (from start to finish), you can find out about your team's standing - how your team fare against other team in the Conference.
The new postseason format for 2023 is explained below.
The new postseason format for 2023 consists of nine teams from each conference that will reach the postseason, with seeds Nos. 1-7 earning a pass to the first round proper (or bye), while seeds No. 8 and No. 9 contest a one-off wild card match to fill the seed No. 8.
That is nine teams from each conference who qualify for the playoff.
Now that the No. 8 seed is filled (after the wild card contest), the division playoff can begin.
There are eight teams from each conference for the division playoff.
Once the first round is set with 16 total clubs (eight in each conference), the (division) playoffs will begin in earnest.
In the past, teams played a single-elimination knockout bracket to decide a champion.
This year (2023 and most likely beyond as well), the first round will be a 'Best-of-three' series that features no draws, meaning a winner must be determined in each of the maximum three matches.
This is similar to how World Cups play their initial group stage.
They play each other three games to determine who comes out of the series.
The first team to notch two victories will advance.
From that point, the playoffs will resume with single-elimination format in the traditional style from the conference semifinals, conference finals, and MLS Cup final.
In other words, from this point on this is a knockout round.
The last team standing at the end of the knockout (round) bracket wins MLS Cup and is generally considered the MLS champion.
Last year's MLS Cup winner was LAFC, who also won the Supporters' Shield.
That feat - winning the two major league titles for both the regular season and postseason - is actually quite rare.
In fact, last year marked just the eighth time since the league was founded in 1996 that the MLS Cup champion was also the Supporters' Shield winner.
A Major League Soccer club's active roster is comprised of up to 30 players. All 30 players are eligible for selection to the game-day squad during the regular season and playoffs.
In addition to the Salary Budget, each MLS club may spend additional funds on player compensation including money from a League-wide allocation pool (General Allocation Money), discretionary amounts of Targeted Allocation Money, the cost of Designated Players outside the Salary Budget, the cost of U22 Initiative Slots outside the Salary Budget, and money spent on the Supplemental Roster (roster slots 21-30).
Up to 20 players, occupying roster slots 1-20, count against the club's 2023 Salary Budget of $5,210,000 and are referred to collectively as the club's Senior Roster.
Clubs are not required to fill roster slots 19 and 20, and clubs may spread their entire Salary Budget across 18 Senior Roster Players.
A minimum Salary Budget Charge will be imputed against a club's Salary Budget for each unfilled Senior Roster slot below 18.
A club may have no more than 20 players on its Senior Roster, subject to the Season-Ending Injury, Injured List, and Loan exceptions. The Maximum Salary Budget Charge for a single player is $651,250.
When do MLS (Championship) Cup Playoffs take place?
MLS Cup Playoffs typically run through November and December (annually).
For more inforamtion about MLS playoffs format, see MLS Cup Playoffs Format
For everything about MLS, see Major League Soccer
The National Women's Soccer League is a professional women's soccer league at the top of the United States league system.
Headquartered in New York City, it is owned by the teams and, until 2020, was under a management contract with the United States Soccer Federation.
The National Women's Soccer League (NWSL) is a twelve-team Division-I women's professional soccer league featuring national team players from around the world.
The NWSL consists of two conferences: Eastern Conference and Western Conference.
The Eastern Conference (six teams as of 2023)
The Western Conference (six teams as of 2023)
Note: The Seatle team name is Olympique Lyonnais Reign, which derived from French words meaning Lion Kingdom.
The game of soccer consists of 11 players each, including the goalie (*).
The basic formation looks like this:
* * * *
* *
* * * *
*
Forwards and wings: Top row.
Up front consists of 4 players called the forwards and wings:
The left wing, the left forward, the right forward, and the right wing.
Basically, the 4 up front players are lining up in a row from left to right in a straight line next to each other.
These 4 players are usually goal scorers.
And each of the 4 up front players are mainly covering/playing his/her own forward and wing area.
Mid-fielders: Middle row (or second row).
Mid-fielders consist of 2 players (sometimes 3 or 4 players depending on the strategies the coach or manager is employing.)
If the strategy is for 2 mid-fielders, which is very common, there would be a left mid-fielder and a right mid-fielder.
Basically, the 2 players are lining up in a row from left to right in a straight line next to each other.
The left mid-fielder is mainly covering/playing the left half of the mid-field area.
And the right mid-fielder is mainly covering/playing the right half of the mid-field area.
If the strategy is for 3 players, which is also very common, there would be a left (wing) mid-fielder, a center mid-fielder, and a right (wing) mid-fielder.
Basically, the 3 players are lining up in a row from left to right in a straight line next to each other.
And each of the 3 mid-fielders is mainly covering/playing his/her own mid-field area.
If the strategy is for 4 mid-fielders, which is NOT very common, there would be a left wing mid-fielder, a right wing mid-fielder, and two center mid-fielders, with the 4 mid-fielders lining up in a row from left to right in a straight line next to each other.
And each of the 4 mid-fielders covering/playing his/her own mid-field area.
Defenders: Last row (or bottom row).
Defenders consist of 4 players.
The left wing defender, the two middle defenders, and the right wing defender.
Basically, the 4 defense players are lining up in a row from left to right in a straight line next to each other.
And each of the 4 defense players is mainly covering/playing his/her own defending area.
Goal Keeper:
The last of the soccer formation is the goal keeper (also known as the goalie).
The goalie can use his/her hands in his/her own goal area only.
Outside of the goal area there will be a goal penalty kick if he/she uses his/her hands to touch any part of the ball.
Mid-fielders Explanation:
If the strategy is for 3 or 4 mid-fielders, the one or two extra players needed would have to come from either the two wing up front players or two defenders; or a combination of the defender and/or wing players.
Conclusion
That is the basic universally employed soccer formation.
Of course, that basic soccer formation will get thrown out completely once the game gets out of hand and/or requires a change in strategy.
Not only that, some leagues or individual teams throughout the world utilizes many formations from game to game -- even within the single game itself due to the flow of the game that requires a change in strategy.
However, the basic universally employed soccer formation shown earlier is the official backbone soccer formation.
Here is a soccer formation utilizes by the Saudi Soccer League and as well as the European Soccer Leagues (i.e., the Premier League, Spanish soccer league La Liga, the German soccer league BundesLiga, just to name a few).
The frontline (top row) consists of two forward players Ronaldo and Benzema:

Note that the frontline (top row above) and the first tier midfielders (2nd row above) are the primary goal scorers.
Here is the complete formation:

As you can see from the illustration above, the frontline (top row) consists of two forward players (Ronaldo and Benzema) but no left wing and right wing players.
The two wing players are pulled back to help midfielders and become first tier midfielders of three players.
The universally adopted (regular) formation of the midfielders is still the same with two players behind the first tier midfielders (of three players).
This creates a two-tier midfielders: 3 players upfront as the first tier; 2 players (behind) as the second tier midfielders.
This is known as 2-3-2 formation or just 2-3-2.
But the defend line is reduced to three players (bottom row) because one of its player is moved up one slot to be one of the two second tier midfielders.
Here are more soccer formations utilized by Australia -- along with England and Spain when they played against each other in the FIFA 2023 Women's World Cup Final.
Spain used a 4-4-2 formation or just 4-4-2.
That is four defenders, four midfielders and two forwards (a total of 10). Of course, the goalie is not factored into the soccer formation for this illustration.
For England, it's a 3-4-1-2 formation or just 3-4-1-2.
This means three defenders (very confident in their defensive line), four (second tier) midfielders, one (first tier) midfielder and two forwards (a total of 10). Of course, the goalie is not factored into the soccer formation for this illustration.
Australia used a 4-4-2 formation, too, in a (1 - 3) loss to England in the semifinal game that sent England to the FIFA 2023 Women's World Cup Final.
Here is Australia's 4-4-2 formation:

In soccer, a substitution is the act of replacing one player with another during the course of a match.
Generally speaking, substitutions are allowed at any time during the game.
However, there are specific rules governing when and how 'subs' can be made.
Some of these rules are applicable to the sport at all levels (from youth soccer to professional soccer), and some are specific to the league or level of play.
Most youth soccer leagues and many amateur soccer leagues utilize a 'rolling subs' rule.
This essentially means you can make any number of substitutions and players are free to substitute in and out of the game as often as desired.
In contrast, in professional soccer leagues, each team is only permitted to make a certain number of substitutions per game.
As of 2023 the number of substitutions allowed in most competitions is 5 per game (an increase from 3 to 5 from prior years).
Many coaches have welcomed the additional flexibility and tactical options the change has afforded them.
We won't focus rules for any other levels other than only for professional and World Cup levels.
So no youth and amateur soccer rules being discussed here.
However, the following rules apply to all soccer games regardless of the level of play (including World Cup levels):
Again, the following rules apply to only for professional and World Cup levels.
As stated above (as of 2023 and beyond), a professional team can make substitutions up to 5 per game.
In certain competitions (such as the World Cup - as of 2023 and beyond), teams are permitted to make an additional substitution in extra time. So it is 6 per game.
Yes! As long as a coach has not used their maximum amount of substitutions, they can replace any of the players on the field regardless of whether that player started the game or previously came on as a substitute themself.
No, substitutions can only be made during a stoppage in play.
This means the team must wait until the ball has gone out of bounds, a goal has been scored, or the referee has stopped play for another reason (e.g., an injured player).
Of course, a team can choose to kick the ball out of bounds themselves to create a substitution opportunity if they so wish!
There are no restrictions on substituting a player who has received a yellow card.
However, a player who has received a red card must leave the field of play immediately and may not be replaced by another player.
Once a player has entered the field of play, the substitution is considered complete. If the coach subsequently wants to take that player off, they must use another substitute to replace them.
Yes, even professional teams make mistakes from time to time and make some ill-advised substitutions and change their mind and forced to make another substitution, wasting valuable substitution usage.
Soccer referees use yellow and red cards to communicate with players and manage the game.
A yellow card is typically shown for minor offenses, while a red card indicates more serious infractions and reckless fouls that warrant immediate dismissal from the game.
A yellow card means a player has received a warning regarding their conduct during the match. Both color cards provide clear instructions to players as to what actions may result in being shown one.
A red card in soccer results in an ejection from the game, while a yellow card is a warning to the player that they are in danger of being ejected.
A player receives a red card after receiving two yellow cards, or if the referee believes that the player has committed a serious infraction (like punching another player).
Once a player receives a red card, they must leave the field of play and cannot be replaced by another player on their team.
Yellow cards are for less serious infractions, such as persistent fouling or delaying the restart of play.
If a player receives two yellow cards in the same game, they are automatically shown a red card and ejected from the game.
Referees typically use yellow cards to warn players against committing certain offenses (e.g., unsportsmanlike conduct).
Yellow cards can be given for a variety of infractions, including:
During a soccer game, a yellow card stays with you until the end of the game.
Remember, a second yellow card in the same game results in a red card and immediate dismissal from the field.
Once the game is over, there is no official rule regarding how accumulated yellow cards are treated.
However, in some leagues, players can be punished for the yellow cards they accumulate through their games.
In the MLS, yellow cards accumulated during the regular season don't carry over to the MLS Cup.
In La Liga competitions like the Copa del Rey, yellow cards outside the competition don't count toward the five-card regulation.
Other leagues have their own sets of rules regarding yellow and red cards, and some may not have penalties for accumulated yellow cards at all.
For all leagues yellow cards do not carry over into the next season.
The answer to this depends on the specific league and its rules regarding yellow card offenses.
For example, two yellow cards in two consecutive soccer matches mean a player will be suspended for the next match.
While you can only get two yellow cards in a single game before receiving a red card and being ejected from the field, there is no specific limit to how many yellow cards you can get over the course of your soccer career.
Spanish defender Sergio Ramos holds the record for most yellow cards, with an astonishing 262 accumulated cards throughout his career.
Referees typically use red cards to punish serious infractions, such as intentionally committing violent acts against another player on the field.
Remember that two yellow cards result in an automatic red card or if the referee believes that the player has committed a particularly serious offense against another player or the rules of the game.
According to soccer rules, some examples of acts that can result in a red card include the following:
A maximum of four players can leave a match due to red cards.
In other words, the team with a red card must play one player short; two red cards 2 players short ; three red cards 3 players short, etc., (this is similar to shorthand play in hockey).
If a fifth player is shown a red card, the referee ends the game immediately and the offending team is forced to forfeit the rest of the game.
The goalkeeper is treated as any other ordinary player on the field, except having the priviledge of using his/her hands to touch the ball in the goal zone/area (only).
This means that a goalkeeper can receive a yellow card and/or a red card just like any other players on the field.
If a goalkeeper receives a red card, they are dismissed just like any other players on the field.
The team is then reduced to 10 players, and the coach must call on a substitute goalkeeper to replace the dismissed one.
A red card means an immediate sending-off from the field, with no substitute allowed.
The team with a red card must play 10 against 11 for the rest of the game.
This can have a huge impact on a game, as the team must now play with fewer players.
Players can also be fined for red card offenses.
While there is no universal rule regarding fining players, many soccer clubs charge fines for red cards.
Usually, a red card results in a one-match suspension when players receive a red card after a second yellow card.
Depending on the circumstances and severity of the offense, a player who receives a red card may be suspended from future games.
A player can be banned for two consecutive matches if they receive a red card due to dissent.
Players who commit serious foul play or violent conduct are suspended for a minimum of three games.
For example, FIFA temporarily suspended Brazilian soccer star Neymar for four matches following a game against Chile.
Another example took place during the 2014 FIFA World Cup, when Luis Suarez bit Italy's Giorgio Chiellini in one of the most shocking incidents in recent soccer history.
He was ultimately banned for nine games and unable to play the rest of the World Cup.
Yes, it is possible for a team to win with only 10 players on the field -- although it is challenging.
If the team loses possession or commits another foul (i.e., another red card) while playing shorthanded, it will put them at a further disadvantage.
Teams playing with fewer players often focus on defensive tactics and keeping possession of the ball instead of trying to score goals.
There you have it -- everything you need to know about soccer.
Now you can watch/play soccer at your leisure with confidence knowing everything you need to know.
Enjoy soccer!
A stoppage time, in soccer, is an extra playing time that is added at the discretion of the referee after regulation play (of 90 minutes) has ended to compensate for stoppages in play caused by injuries, substitutions, or other interruptions.
Remember that in soccer, the regulation time is 90 minutes only, but the clock keeps running from the start to the finish (of the 90 minutes), even when a ball is out of bound or when the game is not being actively played.
This is idle time or wasted time because the clock just keeps running from the start to the finish.
To compensate for those loss time, a stoppage time is added to the regulation time of 90 minutes -- hence, 90 minutes + stoppage time.
The stoppage time is usually about 4 to 8 minutes, depending on the flow of the game.
Enjoy the game of soccer.
Offside is the most confusing rule of the soccer game -- especially more so for people new to the game of soccer.
An offside rule is used to make players play the game fairly without cheating by moving behind the defenders (line) before the ball gets past the last line of defenders.
The key phrase is: past the last line of defenders.
This means that offensive players (usually forward and midfield players -- the frontline players -- goal scorers) cannot move forward past the last line of defenders WHILE the ball is still not travelling past the last line of defenders.
They must stay "at least" inline with the last line of defender(s) WHILE the ball is still not travelling past the last line of defenders.
Once the ball is travelling past the last line of defenders everything is fair game.
You can move forward as many players as you want past any defender(s) and it is fair game.
The key point to remmeber is that, you cannot be ahead of the ball if you're behind the last line of defenders.
You can be behind the last line of defenders if the ball is "already" beyond you (or ahead of you) and you're chasing the ball and not the other way around -- you're not offside.
In that case, you can be miles and miles behind the last line of defenders and you're not offside.
This is to prevent offensive player(s) from cheating by sneaking behind the last line of defender(s) before the ball passes the last line of defender(s).
This rule puts offensive players from having an advantage (or a head start) to the ball and thus making the game more fair.
Think of it this way: The "offside" line is moving with the "last line" of defenders WHILE the ball is still not travelling past the last line of defenders -- and the ball is moving or in the process of moving past the last line of defenders.
This is the case where the offensive player(s) has the posession of the ball and is moving forward with the ball and looking to pass the ball to their teammates and threatening to score on the apposing team.
You cannot pass the ball to your teammates "IF" your teammate is already past the "last line" of defender(s); or you cannot kick the ball forward toward the goal (or toward any area inide the goal area if it is near the goal area) "IF" your teammate is already past the "last line" of defender(s).
The key phrase is: your teammate is already past the "last line" of defender(s).
Your teammate(s) must stay "at least" inline with the last line of defender(s) in order for you to pass the ball to your teammate(s).
This is to prevent cheating and makes the game fair.
In that case, there are no offside violation and you can send as many players behind the last line of their defenders as you wish because the apposing team moved beyond their field of right -- that is, they're moving beyond their half of the field.
When a team moves (or sends) all of their players (with the exception of their goalie) beyond their half of the field, they've waived their right to the offside rule.
Make note: the goalie does not count as a player present in their own half field for the half field offside rule purpose.
In other words, a goalie can be present in their own half field and still not receiving the offside rule protection "IF" a team moves (or sends) all of their "other" players beyond their half of the field -- and therefore, they've waived their right to an offside rule protection.
Yes, teams do that on a regular basis, especially when they're behind and they need to send all of their players beyond their half of the field to bunch up on the apposing team so that they can score goals.
This is the same as hockey where a player cannot pass a puck to his teammate that is already inside the zone line of the apposing team.
But the difference is, in soccer, the offside line is moving with the last line of defender(s) -- while in hockey the offside line stays fixed and not moving.
In soccer, you can be already past the last line of defender and not being called "offside" IF your teammate who has posession of the ball and is moving forward with the ball but "HAVE NOT" passed the ball past the last line of defender.
This is called delay offside and the referee won't blow the whistle because the referee is giving the delay offside player a chance to recover and be "inline" (or onside) and not being "offside".
Once your player is at least inline with the last line of defender(s) you can pass the ball forward and it is fair game.
The key word is "forward".
If you pass the ball latteral or backward, it is still not an "offside" incident yet -- it is still in a delay offside stage.
Only when the ball is moving "forward" past the last line of defender that it is an "offside" incident and the referee will blow the whistle.
On the other hand, if your teammate is already behind the last line of defender and you pass the ball to your teammate (who is already past the last line of defender) or if you kick the ball forward toward the goal in an attempt to shoot the ball and try to score a goal, the referee will blow the whistle to make an offside call -- because the offside rule says that a player cannot be behind the last line of defender when a ball passes the last line of defender.
Two Key Points To Remember:
1. The "offside" line is moving with the "last line" of defenders.
2. Only when the ball is moving "forward" past the last line of defender that it is an "offside" incident and the referee will blow the whistle.
In conclusion: The offside rule is a rule to prevent cheating.
If a player is being called for an offside, it is said to be that the player is caught cheating.
That is it for offside rule.
There you have it -- everything you need to know about soccer.
Now you can watch/play soccer at your leisure with confidence knowing everything you need to know.
Enjoy the game of soccer.
The throw in rule states that the player throwing the ball into the field of play must be outside the white boundary line and his/her foot must not touch any part of the boundary (white) line.
The ball must be above the head of the player throwing the ball and both hands must touch the ball while throwing the ball into the field of play, and both feet must be planted on the ground while throwing the ball into the field of play.
The Throw In Rule Contains Four Things:
1. The foot (or feet) must be outside the white boundary line and must not touch any part of the boundary (white) line.
2. The ball must be above the player's head while throwing the ball.
3. Both hands must touch the ball while throwing the ball.
4. Both feet must be planted on the ground while throwing the ball.
In other words, (1) the feet must be outside the white boundary line while throwing the ball into the field of play and (2) the ball must be above the player's head and (3) the player must hold the ball with both of his/her hands and (4) both feet must be planted on the ground while throwing the ball into the field of play.
In Summary:
You cannot throw the ball into the field of play with just one hand and/or from either side of player's head.
You must use both hands and the ball must be above the player's head while throwing the ball into the field of play.
You cannot jump or lift any foot off the ground while throwing the ball into the field of play.
Whenever a player passes the ball to his/her own goalkeeper using his/her foot the goalkeeper cannot touch that ball with his/her hands, even when this action occurs inside the goal area where the goalkeeper usually handling the ball with his/her hands.
Because a player passes the ball to his/her own goalkeeper using his/her foot it nullifies the goalkeeper's right to use his/her hands to handle the ball.
The ball becomes "live" and "toxic" and the goalkeeper cannot touch it with any of his/her hands.
This is similar to as if the goalkeeper is outside of the goal area where the goalkeeper is just like an ordinary player on the field and cannot touch the ball with any of his/her hand.
Now if a player uses his/her head or any part of his/her body (except the hands/feet) to pass the ball to his/her own goalkeeper then the goalkeeper can legally touch the ball with his/her hands.
For example, a player can use his/her head or any part of his/her body like his/her shoulders, back side, left side, right side, chest, tummy, buttock or even his/her thigh to pass the ball to his/her own goalkeeper and it is legal for the goalkeeper to legally touch the ball with his/her hands.
Only when a player uses his/her foot to pass the ball then the ball becomes "live" and "toxic" and the goalkeeper cannot touch it with any of his/her hands.
You will often see a player passes the ball to his/her own goalkeeper and the goalkeeper receives and handles that ball with his/her own foot/feet (and not with his/her hands) because the goalkeeper cannot touch it with any of his/her hands.
EXCEPTION: The only exception to that rule is when a player throws a ball with his/her both hands to inbound the ball to the goalkeeper [to inside the goalkeeper area] -- and because the player uses his/her hands to handle the ball -- therefore neutralizes the "live" and "toxicity" touching of the ball and the goalkeeper can legally touch it with any of his/her hands.
Note that the goalkeeper can touch it with any of his/her hands only inside the goalkeeper area.
While calling the world's most popular sport "soccer" is typically depicted as a symbol of American ignorance, the reason we don't call it "football" like the rest of the world is because of a feeling of resentment and jealousy toward each other by both sides [the British and Americans].
This root of resentment dated back to the American Revolution when newly independence Americans tried to be different than their forbearance British heritage.
The first act of resentment was the fight for independence from England.
The second act of resentment was the adoption of the new spelling of the English language spearheaded by Noah Webster, the famed inventor of the Webster Dictionary.
[A Side Note: As you are already well-aware today we have the British spellings and the American spellings of certain words in the English language.
The fact that there are British and American spellings of different words is a bane of linguists and study-abroaders in English-speaking countries.
For the different spellings, we can thank those pesky American revolutionaries.
In 1789, Noah Webster of Webster's Dictionary fame spearheaded the push toward "American" variations on some words.
This push for variations was driven by wanting to be different [and to some extent a result of resentment toward their forbearance British heritage].
For the most part, the alterations of the words involved removing "superfluous" (or unnecessary) letters like the U in "colour", "behaviour," or removing "ue" from "catalogue" or removing the ending with "-ise" and replacing it with "-ize" as in "organize", "recorgnize", "realize", "modernize", "characterize", "finalize," and removing the final "-me" in "programme."
One particular un-superfluous or un-necessary word that Noah Webster seemed to get irritated by is the word "grey," the British English word.
Gray is the more popular spelling in the US, while grey reigns supreme in the UK as well as Ireland, Australia, and other places that use British English.
Was there a need to be different in gray verses grey?
Appearantly there was! -- according to Noah Webster -- as to go along with his alteration of the superfluous colour verses color.]
The third act of resentment was the adoption of the game of "soccer" as the official version of American game name.
The word "soccer" is not an American invention -- it was a British invention but for some reason or another [a resentment perhaps?] that British people stopped using only around 40 years ago, according to a 2014 paper by University of Michigan professor Stefan Szymanski.
The word "soccer" comes from the use of the term "association football" in Britain, and goes back 200 years (right around the 1880s).
Really?
How?
.... "soccer" comes from the use of the term "association football" ?
How?
I'm a little skeptical about this link/association of the two words: "soccer" and "association football."
I wish the author of the paper had gone a little bit deeper into the reason as to why the link/association of the two words: "soccer" and "association football."
In the early 1800s, a bunch of British universities took "football" — a medieval game — and started playing their own versions of it, all under different rules.
To standardize things across the country, these games were categorized under different organizations with different names.
One variant of the game you played with your hands became "rugby football."
Another variant came to be known as "association football" after the Football Association formed to promote the game in 1863, 15 years after the rules were made at Cambridge University.
Right around the 1880s "Rugby football" became "rugger" for short, then "rugby" as it is known today.
"Association football" became "soccer" [in Britain].
After these two sports (Rugby and Soccer) spread across the Atlantic, Americans invented their own variant of the game that they simply called "football" in the early 1900s, which is known today to the British as American Football (i.e., the New England Patriots, the Chicago Bears, the Miami Dolphins, etc.)
Then everything got distinguised and different when "Association football" became "soccer" in America, and what was called "gridiron" in Britain became simply "football" in America (i.e., the New England Patriots, the Chicago Bears, the Miami Dolphins, etc.)
The interesting thing here is that Brits still used "soccer" regularly for a huge chunk of the 20th century.
Between 1960 and 1980, "soccer" and "football" were "almost interchangeable" in Britain, Szymanski found.
Then everything changed (via Szymanski):
"Since 1980 the usage of the word 'soccer' has declined in British publications, and where it is used, it usually refers to an American context.
This decline seems to be a reaction against the increased usage in the US which seems to be associated with the high point of the NASL (National Association of Soccer League) around 1980."
Most British people stopped saying "soccer" because of (resentment] of its American connotations, however, UK broadcaster Sky Sports still used it to brand wildly-popular TV shows "Soccer Saturday" and "Soccer A.M."
American football (referred to simply as football in the United States and Canada: i.e., the New England Patriots, the Chicago Bears, the Miami Dolphins, etc.), also known as gridiron, evolved in the United States, originating from the sports of soccer and rugby.
The first American football match was played on November 6, 1869, between two college teams, Rutgers and Princeton, using rules based on the rules of soccer at the time.
A set of rule changes drawn up from 1880 onward by Walter Camp, the "Father of American Football", established the snap, the line of scrimmage, eleven-player teams, and the concept of downs.
There is no clear documentation stating the date and place of origination of today's most popular sport - world football (but we Americans refer to it as soccer).
However, most historians agree that some type of a ball game has been played for at least over 3000 years.
In 1820 in the USA, football (known today as Soccer) was played among the Northeastern universities and colleges of Harvard, Princeton, Amherst and Brown.
In 1848 the rules were further standardized and a new version was adopted by all the schools, college and universities, known as the Cambridge Rules.
In 1862 the first soccer club formed anywhere outside of England was the Oneida Football Club, Boston USA.
There you have it -- everything you need to know about soccer, including its history.
Now you can watch/play soccer at your leisure with confidence knowing everything you need to know.
Enjoy the game of soccer everybody.