16. Learn chess with free “Scid vs PC”

Learn chess with free “Scid vs PC” (commercial “Fritz”)

Scid is a chess DB app. With it you can play chess – browse DBs  of chess games (eg *.pgn game descriptions), edit games (PGNs) and search for games in opened game list by various criteria.

We can paste PGN in Scid (Edit -> paste PGN) or “Open” icon loads file (may contain more PGNs).

Scid chess player uses its own special three-file DB format which is very compact and fast, but it can convert to and from the standard PGN (Portable Game Notation) format. SAN means Standard Algebraic movesNotation eg halfmove “1.e4” – White or “1…e5” – “…” is Black.

Note that scid can read Gzipped PGN file directly, so if you have a large PGN file compressed with Gzip to save disk space, you do not have to un-gzip it first.  (gz archive may contain oly one file e.g. mybase.pgn.gz).

PHP chess players (programming source PHP code)

For me are good only to learn PHP (on Github are 4-5, all unfinished). To learn chess free “Scid vs PC” offers much more. You  eed full time work more monts to achive simmilar functionality with PHP – why waste time ?

Only advantage is using html tags in annotations  (eg <ol> <li>… Scid formats annotations worser, Fritz worser than Scid.)

PGN example of annotated game description

{Example of <b>positional play…} is annotation

( 7…Qe7 {saves R if White plays so :} 8.Qxb7 Qb4+ { forcing Q exchange.} ) is variation “(…)” which contains annotation {…}.
We can play variations and make own variations  – it is best way to learn chess.

My Github repo contains Many PGNs :
https://github.com/slavkoss/fwphp/tree/master/fwphp/glomodul/phpchess/games

[Event “diag. 1 G0001 Koblenz or Koblencs School chess game 1961”]
[Site “opera house in Paris, during Bellini’s opera Norma or Barber of Seville”]
[Date “1858.??.??”]
[Round “?”]
[White “Morphy“]
[Black “konsultants (alleati)”]
[Result “1-0”]
[ECO “C41”]
[Opening “Philidor defense“]
[Annotator “pag. 4 diag 1”]
[PlyCount “33”]
[Comment “Positional play (strategy) preparation for combination.
Black – two strong amateurs: the German noble Karl II, Duke of Brunswick and the
French aristocrat Comte Isouard de Vauvenargues.”]

1. e4 e5 {Example of <b>positional play to prepare combinations</b> in
“Romantic Era” games
:
<ol> <li>rapid development <li>center control <li>open verticals and diagonals <li>value of sacrifices in mating combinations… </ol> }

2. Nf3 d6 {d6 is Philidor’s Defence, named after Francois-Andre Danican
Philidor, the leading chess master of the second half of the 18th century (100
years before Morphy) and a pioneer of modern chess strategy. He was also a noted
opera composer. It is a solid opening, but <b>slightly passive</b>, and it
ignores the important d4-square. Most modern players prefer 2…Nc6, and 2…Nf6
– <b>Petrov Defence</b>.}

3. d4 Bg4 {3…Bg4 is considered an inferior move today. Black to maintain
material equality, he must surrender the bishop. Capturing a knight that has
only moved once (time).
3…Bg4 was accepted theory at the time.[1] Today 3…exd4 or 3…Nf6 are usual.
Philidor’s original idea, 3…f5, is a risky alternative.}

4. dxe5 Bxf3 {If 4…dxe5, then 5.Qxd8+ Kxd8 6.Nxe5 and White wins a pawn and
Black has lost the ability to castle. This knight threatens the bishop on g4 as
well as the f7 square forking the king and rook.
Black can 4…Nd7 5.exd6 Bxd6, when he is down a pawn but has some compensation
in form of better development.
4…Bxf3 Black moves the bishop for a second time to capture a knight that has
only moved once (time). Black also gives up the bishop pair, which weakens the
light squares. }

5. Qxf3 {Steinitz’s recommendation 5.gxf3 dxe5 6.Qxd8+ Kxd8 7.f4 is also good
(doubled pawns
– pawn structure). Morphy prefers to keep the queens on. }
5…dxe5 {After Black recaptures the pawn on e5, White has a significant lead in
development.}

6. Bc4 {is move that has many great attributes: 1. develops a piece. 2.
checkmate is threatened with 7. Qxf7. 3. frees up last square for White to
castle (time, space, and king safety).}
6…Nf6 { BLUNDER After White’s next move, both f7 and b7 will be under attack.
Better is Q protect f7-p making White’s next move less potent.}

7. Qb3
7…Qe7
( {Black’s only good move but blocks f8-B and kingside castling.}
7…Nc6 {leads to mate} 8.Bxf7+ Ke7 {or Kd7} 9.Qe6 )
( 7…Qd7 {Black loses R } 8.Qxb7 {9.Qxa8 can not be stopped}
(8. Qxb7 Qc6? 9.Bb5 {would lose Q})
)
( 7…Qe7 {saves R if White plays so :} 8.Qxb7 Qb4+ { forcing Q exchange.} )

8. Nc3 {(8. Qxb7 Qb4+) Morphy could have won a pawn by 8.Qxb7 Qb4+ 9.Qxb4 Bxb4+.
White can also win material with 8.Bxf7+ Qxf7 9.Qxb7, but Black has dangerous
counterplay after 9…Bc5! and 10.Qxa8 0-0, or 10.Qc8+ Ke7 11.Qxh8 Bxf2+!. “But
that would have been a butcher’s method, not an artist’s.” (Lasker).[2] In
keeping with his style, Morphy prefers rapid development and initiative over
material.

At depth 42 on Stockfish 11 the evaluation for the top 3 moves is as follows:

1. Qxb7 (2.15)
2. Nc3 (2.10)
3. 0-0 (1.61)
}
c6 {The best move, allowing Black to defend his pawn without further weakening
the light squares, which have been weakened by Black trading off his
light-square bishop.}

9. Bg5 {Black is in what’s like a zugzwang position here. He can’t develop the
[Queen’s] knight because the pawn is hanging, the bishop is blocked because of
the Queen.–Fischer}
b5 {Black attempts to drive away the bishop and gain some time, but this move
allows Morphy a strong sacrifice to keep the initiative. This move loses but it
is difficult to find anything better; for example 9…Na6 10.Bxf6 gxf6 11.Bxa6
bxa6 12.Qa4 Qb7 and Black’s position is very weak.}

10. Nxb5 {Morphy chooses not to retreat the bishop, which would allow Black to
gain time for development.}
cxb5 {Black could have prolonged the game by playing 10…Qb4+, forcing the
exchange of queens, but White wins comfortably after either 11.Nc3 or 11.Qxb4
Bxb4+ 12.c3!}

11. Bxb5+ {Not 11.Bd5? Qb4+, unpinning the knight and allowing the rook to evade
capture.}
Nbd7

12. O-O-O Rd8 {The combination of the pins on the knights and the open file for
White’s rook will lead to Black’s defeat.}

13. Rxd7 Rxd7 {Removing another defender.}

14. Rd1 {Compare the activity of the white pieces with the idleness of the black
pieces. At this point, Black’s d7-rook cannot be saved, since it is pinned to
the king by the bishop and attacked by the rook, and though the knight defends
it, the knight is pinned to the queen.}
Qe6 {Qe6 is a futile attempt to unpin the knight (allowing it to defend the
rook) and offer a queen trade, to take some pressure out of the white attack.
Even if Morphy did not play his next crushing move, he could have always traded
his bishop for the knight, followed by winning the rook.}

15. Bxd7+ Nxd7 {If 15…Qxd7, then 16.Qb8+ Ke7 17.Qxe5+ Kd8 18.Bxf6+ gxf6
19.Qxf6+ Kc8 20.Rxd7 Kxd7 21.Qxh8 and White is clearly winning. Moving the king
leads to mate: 15…Ke7 16.Qb4+ Qd6 (16…Kd8 17.Qb8+ Ke7 18.Qe8#) 17.Qxd6+ Kd8
18.Qb8+ Ke7 19.Qe8# or 15…Kd8 16.Qb8+ Ke7 17.Qe8#.}

16. Qb8+ {Morphy finishes with a queen sacrifice.}
Nxb8

17. Rd8# 1-0

World Chess Champions

Chess Player Directory (chessgames.com)

Text (part) and images (i001…) in this page are from page
https://en.wikipedia.org/wiki/World_Chess_Championship
.

See also “The golden treasury of chess” (till 1969) by I. AL HOROWITZ
Dedicated To H. N. Pillsbury (1872-1906)

Carlsen  i001 Current (2021) world champion is Magnus Carlsen of Norway  2013-… He defeated Viswanathan Anand in 2013.The chess games of Magnus Carlsen

Kasparov used some of openings from his DB while coaching Magnus Carlsen. In 2009. Under Kasparov’s tutelage, Carlsen became the youngest ever to achieve FIDE rating higher than 2800, and the youngest ever world number one. Carlsen 2014:
https://chess24.com/en/read/news/magnus-carlsen-on-reddit-ask-me-anything Particularly impressed by the 1994 Candidates match between Anand and Kamsky.

2014 Candidates by Anand’s win against Aronian in the first round – It’s not often that you beat the number 2 player in the world purely by technique.

https://chess24.com/en/read/news/candidates-round-1-the-tiger-is-back
.
His favorite chess book is Kramnik: My Life & Games. Carlsen : In order to become a Master or an International Master, I think you can start later and it’s more about putting in the time and hard work rather than talent. Anand, Kramnik, Topalov and Svidler. I prefer to give mainstream openings my own spin.

What’s your favorite non-chess book? Close race between several Donald Duck comics (seriously).

Unofficial champions (pre-1886)  – Pre-Morphy period ~350 years
1510-1850

Leading players before the World Chess Championships

Name Year Country Age
Ruy López de Segura 1559–1575 Spain 29–45
Leonardo di Bona c.1575 Naples 33
Paolo Boi c. 1575 Sicily 47
Alessandro Salvio c. 1600 Naples c. 30
Gioachino Greco c. 1620–1634 Naples c. 20–34
Legall de Kermeur c. 1730–1755 France c. 28–53
François-André Danican Philidor 1755–1795 France 29–69
Alexandre Deschapelles 1815–1821 France 35–41
Louis-Charles Mahé de La Bourdonnais 1821–1840 France 26–45
Howard Staunton 1843–1851 England 33–41
Adolf Anderssen 1851–1858 Prussia 33–40
Paul Morphy 1858–1862 United States 21–25
Adolf Anderssen 1862–1866 Prussia 44–48
Wilhelm Steinitz 1866–1886 Austria-Hungary 30–50
Johannes Zukertort 1878–1886 England 36–44

EDO years 1850, 1851, 1858, 1870, 1877

Player                                                                                 1850       1851      1858     1870    1877

1. Morphy, Paul 2719 2741 2801
2. Baron Tassilo von Heydebrand und der Lasa 2692 2720
3. Anderssen, Adolf 2634 2673 2635 2687 2596
4. Petrov, Alexander 2621 2627 2629
5. Staunton, Howard 2609 2607
6. Löwenthal, Johann 2630
7. Paulsen, Louis 2627 2633
8. Steinitz, Wilhelm 2725 2768
9. Neumann, Gustav 2663
10. Mackenzie, George 2636
11. Potter, William 2619
12. Zukertort, Johannes 2645
13. Blackburne, Joseph 2604

Renaissance. By 1510 the old type of chess was obsolete in most of Italy and
Spain. Analysis was the ruling motive in the literature of the period. Openings
known today as the Ruy Lopez, Giuoco Piano, Petroff defense, Philidor Defense,
Bishop’s Opening and Queen’s Gambit Accepted
, were first outlined in a late 15th
century manuscript (in the Gottingen University Library).

Ruy Lopez (from Philip
II court) first appears in 1559 when this Spanish priest visited Italy and
defeated all the Roman players.

After Greco’s death in 1634, Italy produced no
outstanding players for over a hundred years.  1669, a French translation
of his collection of games  was published in Paris.

18th century coffee-houses of London and Paris were the leading centers of
chess activity ( Cafe de la Regence in Paris and Slaughter’s Coffee House in
London).  Andre D. Philidor was musician (1775 till death in 1795 he spent
spring of each year in London and the rest of the year in Paris). He was the
first to define and explain the principles of chess strategy and tactics.

First half of the 19th century Captain W. D. Evans discovered his gambit in
1824,  William Lewis,  great Howard Staunton from 1843 best. In France
Alexander Deschapelles; Pierre de Saint-Amant (“French Defense).  Central
Europe  B. Horwitz,  Russian Petroff (Petrov), Livonian, Kieseritzky.

From a purely technical point of view games of 350 years to 19th century are
not of vital importance
but one wonders whether all gains (theory, knowledge,
systematic analysis ) compensate for  spirit of freshness, of eternal
adventure, of naivete, charm, their sociable and leisurely character.

Romantic Era of chess in the second half of the 19th century was all about
gambits, sacrifices, open lines, and active pieces. Attack at all costs! Defense
is for cowards.  Fell into decline as its failures mounted against the more
pragmatic and dogmatic teachings of Wilhelm Steinitz and Siegbert Tarrasch in
the late 19th  and early 20th.

De La Bourdonnais i002 De La Bourdonnais, the world’s strongest player from 1821 to his death in December  1840

The chess games of Louis Charles Mahe De La Bourdonnais

Something resembling (Appear like; be similar,  corresponding, matching) a world championship match was the La  Bourdonnais – McDonnell chess matches in 1834, in which La Bourdonnais played a series of six matches – and 85 games – against the Irishman Alexander McDonnell, with La Bourdonnais winning a majority of the games.The idea of a chess world champion goes back at least to 1840, when a columnist in Fraser’s Magazine wrote, “Will Gaul continue the dynasty by placing a fourth Frenchman on the throne of the world? — the three last chess chiefs having been successively Philidor, Deschapelles, and De La Bourdonnais.”

i007HowardStaunton  i007 Howard Staunton After La Bourdonnais’s death [3] Englishman Howard Staunton won vs Pierre Charles Fournier de Saint-Amant, in 1843

The chess games of Howard Staunton

A letter quoted in The Times on 16 November 1843, but probably written before that, described the second Staunton vs Saint-Amant match, played in Paris in November–December 1843, as being for “the golden sceptre of Philidor.”[1] The earliest recorded use of the term “World Champion” was in 1845, when Howard Staunton was described as “the Chess Champion of England, or
… the Champion of the World”.[5]Howard Staunton is considered to have been the strongest chess player in the world during 1840s.The first known proposal that a contest should be defined in advance as being
for recognition as the world’s best player was by Ludwig Bledow in a letter to Tassilo von der Lasa, written in 1846 and published in the Deutsche Schachzeitung in 1848: “… the winner of the battle in Paris [in 1843, when Staunton defeated St. Amant] should not be overly proud of his special position, since it is in Trier that the crown will first be awarded.” This was in reference to a proposed tournament to be held in Trier, where von de Lasa resided; but Bledow died in 1846 and the proposed tournament did not take place.[1] Similarly, the London 1851 chess tournament was described beforehand by some contemporary commentators as being for the world championship,[6] but there is no mention afterwards in the tournament book by Staunton.[7]

i003Staunton and Pierre Saint-Amanti003 Jean Henri Marlet : Howard Staunton vs Pierre Saint-Amant
, on 16 December 1843. This chess match was regarded as an
unofficial world championship.
i005Morphy_Löwenthal_1858.jpg  i005, i004 Paul Morphy playing against Hungarian chess master Johann Löwenthal 1858.

The chess games of Paul Morphy

Morphy  at twelve years of age defeated visiting Hungarian master Johann Loewenthal in a three game match.Morphy played matches against several leading players, crushing them all.[11][12]Morphy’s sudden withdrawal from chess at his peak led to his being known as
“the pride and sorrow of chess

i004Paul_Morphy_Daguerreotype.jpg  i004 Paul Morphy a chess prodigy from New Orleans Louisiana, United States.

Dominated all of his opposition during his brief chess career. Due to his astounding achievements, an official World Championship match was only held after his death.Rich child, greatest natural chess talent. 1858 defeated Anderssen and many other Europeans and retited when was 22 years old (declined to play or discuss chess).
Article in Harper’s Weekly (9 October 1858; by C.H. Stanley) was uncertain
about whether Morphy vs Harrwitz match was being for the world championship.[6] Soon after, Morphy offered pawn and move odds to anyone who played him. Finding no takers, he abruptly retired from chess the following year, but many considered him the world champion until his death in 1884.Brilliancy and accuracy of combinations, radical innovator. It was he who introduced the innovation which proved to be a death-knell (smrtno zvono) of romantic type of chess in which brilliancy was the be-all and end-all of every game. Correctness of his moves instead useless sacrifices.
Intuitive with the logical as only the great artist can.  Note how quickly
Morphy made converts.Many report that he was able to recite from memory nearly the entire Civil Code of Louisiana (3,500 articles). Fischer  and Viswanathan Anand ranked Morphy among the ten greatest chess players of all time. Fischer described him as “perhaps the most accurate player who ever lived“. Morphy learned to play chess by watching games between his father and uncle.
Morphy was a player who intuitively knew what was best, and in this regard he has been likened to Jose Capablanca. He was, like Capablanca, a child prodigy; he played quickly, would draw or even win games despite getting into bad positions. Anderssen said that, after one bad move against Morphy, one might as well resign. Garry Kasparov said that Morphy realized quarter-century before Wilhelm Steinitz had formulated principles :

  1. fast development of the pieces
  2. domain of the centre
  3. opening lines – verticales, diagonales, horizontales

Reuben Fine : “[Morphy’s] glorifiers went on to urge that he was the most
brilliant genius who had ever appeared But if we examine Morphy’s record and games critically, we cannot justify such extravaganza. He was so far ahead of his rivals that it is hard to find really outstanding examples of his skill.”

Born to a wealthy and distinguished (ugledna) family in New Orleans 1837, died on July 10. 1884 at the age of 47 by stroke brought on by entering cold water in his bathtub after a long walk in the midday heat. The Morphy mansion 417 Royal Street which backs up to Bourbon Street, sold by the family in 1891, became the site of the well-known restaurant Brennan’s.  In accord with the prevailing sentiment of the time, Morphy esteemed chess only as an amateur activity, considering the game unworthy of pursuit as a serious occupation. Chess professionals were viewed in the same light as professional gamblers.  Morphy was never able to establish a successful law practice – 1861 outbreak of the American Civil War, suffered from delusions of persecution (chasing, progon). He lived a life of idleness, living off his family’s fortune, was cared by his sister and mother.

i006Anderssen   i006  German Adolf AnderssenThe chess games of Adolf Anderssen

1851 new age :  first International Chess Tournament in London, Adolph
Anderssen of Berlin won – Another great player, almost as great as Morphy, and in the opinion of some capable judges even superior to him. Anderssen was best about ten years before Morphy’s appearance. Also brilliancy and accuracy of combinations. Anderssen died of a heart attack at the age of 60.Morphy  vs Anderssen 1858  7-2, 2 draws, after which Morphy was toasted across the chess-playing world as the world chess champion.Anderssen is seen as the world’s leading player from 1851, until he was defeated by Paul Morphy in 1858. After Morphy’s retirement from chess, Anderssen was regarded as the strongest active player, especially after winning the London 1862 chess tournament.
The 1851 London tournament was won by Adolf Anderssen, establishing
him as the world’s leading player.[8] Anderssen has been described as the
first modern chess master.[9] However, there is no evidence that he was widely acclaimed at the time as the world champion, although in 1893 Henry Bird retrospectively awarded the title to Anderssen for his victory.[10]

i006Anderssen

From 1866

The first generally recognized world championship took place in 1886, when the two leading players in the world, Wilhelm Steinitz and Johannes
Zukertort
, played a match, which was won by Steinitz.

From 1886 to 1946, the champion set the terms, requiring any challenger to raise a sizable stake and defeat the champion in a match in order to become the new world champion. Following the death of reigning world champion Alexander Alekhine in 1946, FIDE (the International Chess Federation) took over administration of the World Championship, organizing their first championship in a 1948 tournament.

In 1993, reigning champion Garry Kasparov broke away from FIDE,
which led to a rival claimant to the title of World Champion for the next
thirteen years. The titles were unified at the World Chess Championship
2006
, with the unified title again administered by FIDE.

Since 2014, the schedule has settled on a two-year cycle with a  championship held in every even year.

Though the world championship is open to all players, there are separate
events and titles for the Women’s World Chess Championship, the World
Junior Chess Championship (for players under 20 years of age, though there are younger age events also), and the World Senior Chess Championship (for men above 60 years of age, and women above 50). There are also faster time limit events, the World Rapid Chess Championship and the World Blitz Chess Championship. The World Computer Chess Championship is open to computer chess programs and hardware.

Since 2013, the Candidates Tournament has been an 8-player double round robin tournament, with the winner playing a match against the champion for the title. The Norwegian Magnus Carlsen won the 2013 Candidates and then convincingly defeated Anand in the World Chess Championship 2013.[66][67]

Beginning with the 2014 Championship cycle, the World Championship has followed a 2-year cycle: qualification for the Candidates in the odd year, the Candidates tournament early in the even year, and the World   Championship match late in the even year. Each of the past three cycles has resulted in Carlsen successfully defending his title: against Anand in 2014;[68] against Sergey Karjakin in 2016;[69] and against Fabiano Caruana in 2018. His last two defences were decided by tie-break in rapid games.[70]

The COVID-19 pandemic disrupted the 2020 Candidates Tournament, causing the next world title match to be postponed from 2020 to 2021.[71]

i008Wilhelm_Steinitzi008  1866, Wilhelm Steinitz narrowly defeated
Anderssen in a match (8-6, 0 draws).The chess games of Wilhelm Steinitz

Age of Steinitz 10 years till 1890

Against Johannes Zukertort in 1872 (7-1, 4 draws).
Vienna 1873 chess tournament
Against Joseph Henry Blackburne by a crushing 7-0 (0 draws) in 1876.
Zukertort
 1886, won by Steinitz.
Mikhail Chigorin in 1889,
Isidor  Gunsberg in 1891, and Chigorin again in 1892.

Steinitz was genius accused “destroyed brilliancy in chess” – not true.

Steinitz the first master of positional chess, was a strikingly (impressing, hitting, prominent) brilliant player, not only as a mettlesome (spirited, proud and unbroken spirit) youngster, but even as a feeble (lacking in force, effectiveness, strength, vigour, strength, vitality, dynamism, energy) old man.

L1: Game No. 73 shows us how Steinitz played at the beginning of his career –
enthusiastic disciple of the attacking school. Very shortly thereafter he
experienced a thoroughgoing conversion. He became obsessed with the
deeply-rooted carelessness, flashiness (exhibitionism, immodesty, tasteless
showiness) and frequent unsoundness of attacking school oposed to
combinations of Morphy, with their :

  1. natural development
  2. logical preparation
  3. accurate execution

A pervasive interest in the defense became his life-time passion (desired
intensely); he was fascinated by the idea of refuting (prove to be false or
incorrect)  an unsound attack, of demonstrating to the opponent that one
cannot lightly toss away pawns, or worse pieces, without retribution, that
hit-or-miss and helter-skelter attacks should not be permitted to achieve their
goal. All have absorbed fundamentals of his theories,  whether they have
agreed with him or agreed to disagree also poets of the chessboard as Zukertort, Tchigorin and Blackburne – their attacking play was purified and raised to finer artistic levels by Steinitz’s probing and fruitful criticism.

In the classical period (say, from Steinitz till 1935 Nimzowitsch’s death)
most players were technicians, with Capablanca as the most famous example.

Apart from the Blackburne match, Steinitz played no  competitive chess from 1874 to 1882. During that time, Zukertort emerged as the world’s leading active player, winning the Paris 1878 chess tournament. Zukertort then won the London 1883 chess tournament by a convincing 3-point margin, ahead of nearly every leading player in the world, with Steinitz finishing second.[13][14] This tournament established Steinitz and Zukertort as the best two players in the world, and led to a match between these two, the World Chess Championship 1886,[14][15] won by Steinitz.

Official champions before FIDE (1886–1946)
The reign of Wilhelm Steinitz (1886–1894) –
Wilhelm Steinitz dominated chess from 1866 to 1894. Some commentators date his time as World Champion from 1866; others from 1886.

1889 tournament in New York to select a challenger for Steinitz, rather like the more recent  Candidates Tournaments. Chigorin and Max Weiss tied for first place; their play-off resulted in four draws; and neither wanted to play a match against Steinitz – Chigorin had just lost to him, and Weiss wanted to get back to his work for the Rothschild Bank. The third prizewinner Isidor Gunsberg was prepared to play Steinitz.

  i009Emanuel_Laskeri009 Emanuel  Lasker (1894–1921) – won the 1894 match and succeeded Steinitz as world champion.

The chess games of Emanuel Lasker

Lasker was the World Champion for 27 years consecutively from 1894 to 1921, the longest reign of a World Champion.During that period, he played 7  one-sided World Championship matches against Steinitz, Frank Marshall, Siegbert Tarrasch and Dawid Janowski, and was only seriously threatened in a tied 1910 match against Carl Schlechter..Two young strong players emerged in late 1880s and early 1890s: Siegbert
Tarrasch and Emanuel Lasker
.[28] Tarrasch had the better tournament results at the time, but it was Lasker who was able to raise the money to challenge Steinitz.[28]

Modern Chess 15 years 1890 till 1905

Era of what is called, occasionally in rather a disdainful (insulting) tone,
“modern chess” –  great Lasker and Tarrasch, Schlechter and Maroczy, of the attacking geniuses Pillsbury (lived 34 years, seem to be adequately appreciated 1956 first ed.) and Marshall and Janowski. Positional chess begins to be pre-eminent; before the opponent can be finished off with a brilliant combination.

It is generally necessary to outplay him positionally, in order to create
favorable conditions for sacrificial play. That is why Emanuel Lasker once wrote: “If you play well positionally, the combinations will come of
themselves.”

Lasker: endgame mastery, the first chess psychologist, greatest defensive (save lost positions) player ever, World Champion 27 years. Lasker calculated extremely deeply, seeing things that others would never find resulting in great
combinations, just like all the other great tacticians. Chaotic tactical tidal
waves (like Tal did), which drowned one opponent – defensive setups that even modern computers are incapable of seeing.

Lasker was the first champion after Steinitz; although he did not defend his title in 1897–1906 or 1911–1920, he did string together an impressive run of tournament victories and dominated his opponents. His success was largely due to the fact that he was an excellent practical player. In difficult or objectively lost positions he would complicate matters and use his extraordinary tactical abilities to save the game.

Lasker’s negotiations for title matches from 1911 onwards were extremely controversial. In 1911 he received a challenge for a world title match against José Raúl Capablanca and, in addition to making severe financial demands, proposed some novel conditions: the match should be considered drawn if neither player finished with a two-game lead; and it should have a maximum of 30 games, but finish if either player won six games and had a two-game lead (previous matches had been won by the first to win a certain number of games, usually 10; in theory such a match might go on for ever). Capablanca objected to the two-game lead clause; Lasker took offence at the terms in which Capablanca  criticized the two-game lead condition and broke off negotiations.[29]

Further controversy arose when, in 1912, Lasker’s terms for a proposed match with Akiba Rubinstein included a clause that, if Lasker should resign the title after a date had been set for the match, Rubinstein should become world champion (American Chess Bulletin, October 1913).[30]

  i010José_Raúl_Capablanca_1931The chess games of Jose Raul Capablanca

Capablanca, Alekhine and Euwe (1921–1946)

i010 José Raúl Capablanca World Champion 1921 to 1927.

Moderns, Hypermoderns and Eclectics 37 years 1905 till 1942

Rubinstein, Nimzovich, Bernstein, Capablanca, Duras, Tartakower, Spielmann, Vidmar… They  applied in their games what they had learned from the reigning gods of the chessboard, but they also rebelled, as is the way of youth, and made their own additions and corrections.  Nimzovich and his young countryman Alekhine were evolving a new school of chess thought, whose effect, if not always its objective, was to turn the current chess theories upside down.
During and after the World War I, these players were joined by such masters as Reti, Bogolyubov and Breyer,  still younger players, such as Euwe,
Flohr, Kashdan, Fine, Reshevsky, Botvinnik and Keres. It is an age where
“anything goes”, older masters were rarely capable of such elasticity and
objectivity.

Steinitz: the first master of positional chess. Alekhine: dynamic,
combinative genius. Capablanca: endgame mastery and positional elegance. Tal:  attack and tactics.

Russia’s  
Alexander Alekhine
(later baturalized French), Kasparov’s main early
influence
,  took the world title from Cuba’s Capablanca in a  legendary
World Championship match held in Buenos Aires, Argentina, in 1927 – 34 games, the longest until Garry’s first match with Karpov lasted a record 48.  31 game was mostly quin’s gambit, most draw, both Alekhine and Capablanca said “no advance in chech“.

He proposed the short-lived “London Rules” for future World
Championship matches.

1914 Saint Petersburg tournament – champion must be prepared to defend his title once a year; the match should be won by whichever player first won six or eight games (the champion had the right to choose); and the stake should be at least £1,000 (about £100,000 in current terms).[29]

When Lasker resumed negotiations with Capablanca after World War I, Lasker insisted on a similar clause that if Lasker should resign the title after a date had been set for the match, Capablanca should become world champion.[29] On 27 June 1920 Lasker abdicated in favor of Capablanca because of public criticisms of the terms for the match, naming Capablanca as his successor (American Chess Bulletin, July August 1920). Nonetheless Lasker agreed to play a match against Capablanca in 1921, announcing that, if he won, he would resign the title so that younger masters could compete for it. Capablanca won their 1921 match easily.[20]

Following the controversies surrounding his 1921 match against Lasker, in 1922 world champion Capablanca proposed “London Rules“: the first player to win six games would win the match; playing sessions would be limited to 5 hours; the time limit would be 40 moves in 2½ hours; the champion must defend his title within one year of receiving a challenge from a recognized master; the champion would decide the date of the match; the champion was not obliged to accept a challenge for a purse of less than US$10,000 (about $140,000 in current terms); 20% of the purse was to be paid to the title holder, and the remainder being
divided, 60% going to the winner of the match, and 40% to the loser; the highest purse bid must be accepted. Alekhine, Bogoljubov, Maróczy, Réti, Rubinstein, Tartakower and Vidmar promptly signed them.[31]

i011Alexandre_Alekhine   i011 Alexander Alekhine
– played dynamic and imaginative chess, was World Champion
from 1927 to 1935 and again from 1937 to his death in 1946.

The chess games of Alexander Alekhine

He is the only World Champion to die while holding the title.Alekhine easily won two title matches against Efim Bogoljubov in 1929 and 1934.Alekhine agreed to place future matches for the world title under the auspices of FIDE, except that he would only play Capablanca under the same conditions that governed their match in 1927 – “London Rules”.[32] . Negotiations dragged on for several years, often breaking down when agreement seemed in sight.[20].The only match played under those rules was Capablanca vs Alekhine in 1927.[32] Alekhine, Rubinstein and Nimzowitsch had all challenged Capablanca in the early 1920s but only Alekhine could raise the US$10,000 Capablanca demanded and only in 1927.[33]Capablanca was shockingly upset by the new challenger. Before the match, almost nobody gave Alekhine a chance against the dominant Cuban, but Alekhine overcame Capablanca’s natural
skill with his unmatched drive and extensive preparation (especially deep opening analysis, which became a hallmark of most future grandmasters)
. The aggressive Alekhine was helped by his tactical skill, which complicated the game.Although FIDE wished to set up a match between Alekhine and Bogoljubow, it made little progress and the title “Champion of FIDE” quietly vanished after Alekhine won the 1929 world championship match that he and Bogoljubow themselves arranged.[43]

i012Max_Euwe_1963i012 Dutch Max Euwe, an amateur player who worked as a mathematics teacher. In 1935 Alekhine was  unexpectedly
defeated by Euwe.Alekhine convincingly won a rematch in 1937. World War II temporarily prevented any further world title matches, and
Alekhine remained world champion until his death in 1946.
AVRO tournament in 1938 was won by Paul Keres under a tie-breaking rule, with Reuben Fine placed second and Capablanca and Flohr in the bottom places; and the outbreak of World War II in 1939 cut short the controversy.[44][45]

Financing

Before 1948 world championship matches were financed by  arrangements similar to those Emanuel Lasker described for his 1894 match with Wilhelm Steinitz: either the challenger or both players, with the assistance of financial backers, would contribute to a purse; about half would be distributed to the winner’s backers, and the winner would receive the larger share of the remainder (the loser’s backers got nothing). The players had to meet their own travel, accommodation,
food and other expenses
out of their shares of the purse.[34] This system evolved out of the wagering of small stakes on club games in the early 19th century.[35]

Up to and including the 1894 Steinitz–Lasker match, both players, with their backers, generally contributed equally to the purse, following the custom of important matches in the 19th century before there was a generally recognized world champion. In the early 1920s, Alekhine,
Rubinstein and Nimzowitsch all challenged Capablanca, but only Alekhine was able to raise the US$10,000 that Capablanca demanded, and not until 1927.[33][39]

FIDE title (1948–1993)
FIDE, Euwe and AVRO

Birth of FIDE’s World Championship cycle (1946–1948)

Before 1946 a new World Champion had won the title by defeating the former champion in a match. Alexander Alekhine’s death in 1946 created an interregnum that made the normal procedure impossible. The situation was very confused.

i013Botvinnik_1936  i013 Mikhail Botvinnik was the first World Champion under FIDE jurisdiction – won 1948 (to 1963) Championship Tournament – Two of the participants at AVRO – Alekhine and former world champion José Raúl Capablanca – had died;
Max Euwe, from the Netherlands; Botvinnik, Paul Keres and Salo Flohr from the Soviet Union; and Reuben Fine and Samuel Reshevsky from the United States. However, FIDE soon accepted a Soviet request to substitute Vasily Smyslov for Flohr, and Fine dropped out in order to continue his degree studies in psychology, so only five players competed. Botvinnik won convincingly and thus became world champion, ending the interregnum.[46]The chess games of Mikhail Botvinnik

Period of Russian Hegemony and Fischer 27 years 1942 till 1972

Russian government, acting as sponsors – Botvinnik, Smyslov, Bronstein,
Keres, Geller, Tal… – peak of technical perfection, great emphasis on
openings
. Hordes of analysts finecomb existing ideas extensively and
occasionally produce interesting innovations.

Ukrainian-Soviet Grandmaster David Bronstein (200 Open Games) came as close as one can get to becoming world champion without achieving the highest title. He drew a world championship match against the mighty Mikhail Botvinnik  in 1951, but the champion retained the title with a draw. Bronstein would remain one of the strongest and most creative players in the world for many years.

Drawn 12–12 – Botvinnik-Bronstein in 1951 and Botvinnik-Smyslov in 1954 – so Botvinnik retained the title both times.

The eventual solution was very similar to FIDE’s initial proposal and to a
proposal put forward by the Soviet Union (authored by Mikhail Botvinnik). The 1938 AVRO tournament was used as the basis for the 1948 Championship Tournament.
The AVRO tournament had brought together the eight players who were, by general acclamation, the best players in the world at the time.

FIDE system (1949–1963)

Botvinnik lost to Vasily Smyslov in 1957 but won the return match in
1958, and lost to Mikhail Tal in 1960 but won the return match in 1961.

Thus Smyslov and Tal each held the world title for a year, but Botvinnik was world champion for rest of the time from 1948 to 1963.

The return match clause was not in place for the 1963 cycle. Tigran Petrosian won the 1962 Candidates and then defeated Botvinnik in 1963 to become world champion.

i014Smyslov i014 The chess games of Vasily Smyslov

Vasily Smyslov, World Champion 1957-1958.

i015Mikhail_Tal_1962  i015 Mikhail Tal, World Champion 1960-1961.

The chess games of Mikhail Tal

i016igran_Petrosian_1962  i016 Tigran Petrosian, World Champion 1963-1969.

The chess games of Tigran V Petrosian

i017Bobby_Fischer_1972  i017 Bobby Fischer in Amsterdam meeting FIDE officials in 1972. His reign as World Champion ended, for a short time, 24 years of Soviet domination of the World Championship. After becoming World Champion, Fischer did not play competitive chess for 20 years.

The chess games of Robert James Fischer

Fischer won the 1992 Fischer–Spassky rematch decisively with a score of
10–5 (Yugo dollars). After the 1962 Candidates, Bobby Fischer publicly alleged that the Soviets had colluded to prevent any non-Soviet – specifically him – from winning. He claimed that Petrosian, Efim Geller and Paul Keres had prearranged to draw all their games, and that Korchnoi had been instructed to lose to them. Yuri Averbakh, who
was head of the Soviet team, confirmed in 2002 that Petrosian, Geller and Keres arranged to draw
all their games in order to save their energy for games against non-Soviet players.[50] Korchnoi, who defected from the USSR in 1976, has never alleged he was forced to throw games. FIDE responded by changing the format of future Candidates Tournaments to eliminate the possibility of  collusion.

i018Boris_Spasski  i018 Boris Spassky lost the title match to Petrosian in 1966, but won and became world champion in 1969.[52][53]
i019KarpovThe chess games of Anatoly Karpov

Karpov and Kasparov (1975–1993)

i019 Anatoly Karpov became World Champion after Fischer refused to
defend his title. He was world champion from 1975 to 1985, and FIDE World
Champion from 1993 to 1999 when the world title was split.

Last 50 years ~1970 – 2020

English Grandmaster Mickey Adams has been England’s top player for two decades, he never reached a World Championship match like his countryman Nigel Short, who faced Garry in 1993.

Grandmaster Yasser Seirawan is a four-time US champion who became one of America’s top international players in the post-Fischer era.

Karpov, and especially the 9th World Champion, Tigran Petrosian,
were brilliant at playing quietly until their opponents slipped up. – said
Garry Kasparov. Garry once called Ukraine’s Vassily Ivanchuk
the player who has most surprised me over the board.

Karpov defended his title twice against ex-Soviet Viktor Korchnoi, first in
Baguio, the Philippines, in 1978 (6–5 with 21 draws) then in Merano in 1981 (6–2, with 10 draws).

An unbroken line of FIDE champions had thus been established from 1948 to 1972, with each champion gaining his title by beating the previous incumbent.
This came to an end when Anatoly Karpov won the right to challenge Fischer in 1975.

Karpov eventually lost his title to Garry Kasparov, whose aggressive tactical style was in sharp contrast to Karpov’s positional style. The two of them fought five incredibly close world  champ matches, 1984, 1985, 1986, 1987, 1990. In the five matches Kasparov and Karpov played 144 games with 104 draws, 21 wins by Kasparov and 19 wins by
Karpov
.

i020Garri_Kasparov   13. i020 Garry Kasparov defeated Karpov 1985.

The chess games of Garry Kasparov

He was undisputed World Champion from 1985 to 1993, and held the split title until 2000. Garry is by many as the greatest chess player of all time,  youngest World Chess Champion in history in 1985 at the age of 22 by beating Anatoly Karpov. Winning remarkable 16th game gave Garry a big lead in his 1986 World Championship title defense against Karpov. He’d won four games against only one loss. Incredibly, Garry then lost the next three games in a row and the match was tied with five games remaining. Garry retook the lead by winning game 22 and the final two games were drawn.Garry lost the 2000 World Championship match in London to Russia’s Vladimir Kramnik with a score of 6.5-8.5, with two losses and thirteen draws, no wins – 2nd time in chess history.  Garry retired from professional chess in 2005. Garry won
Linares a record 9 times, including his last official event before retiring in 2005.In February 1996, he defeated IBM’s chess computer Deep Blue
(Computer)
with three wins and two draws and one loss. 1997 Deep Blue
defeated Kasparov 3½-2½ in a highly publicised six-game match. The match was even after five games but Kasparov lost Game 6 – Deep Blue vs
Kasparov, 1997
– to lose the match. This was the first time a computer had
ever defeated a world champion in match play.Kramnik – Deep Fritz (for million dolars Bahrein, Oct. 2002) was 3 : 1 but ended 4 :4. Kramnik – Deep Fritz (fond half million dolars) Bonn 2006, 2 : 4.Since his retirement 2005, Kasparov has concentrated much of his time and energy in Russian politics. He is also a prolific author, most famously his My
Great Predecessors
series.

i021Vladimir_Kramnik_2018   i021 i021Vladimir_Kramnik_2018 (2006–2007 world champ) is of rare players rating over 2800 (first was
Kasparov).

The chess games of Vladimir Kramnik

Vladimir Kramnik defeated Garry Kasparov in 2000, and then after much controversy became the undisputed world champion by beating Topalov in World Chess Championship 2006 reunification match, late 2006. This match, and all subsequent championships, have been administered by FIDE.

i022Viswanathan_Anand_(2016)   i022 Viswanathan_Anand_(2016) (2007–2013) 

The chess games of Viswanathan Anand

Viswanathan Anand, famed for his ultra-rapid play, Indian, held the FIDE title from 2000 to 2002, and the unified title from 2007 to 2013.Kramnik played to defend his title at the World Chess Championship 2007 in Mexico. This was an 8-player double round robin tournament, the same format as was used for the FIDE World Chess Championship 2005. This tournament was won by Viswanathan Anand, thus making him the World Chess Champion. Because Anand’s World Chess Champion title was won in a tournament rather than a match, a minority of commentators questioned the validity of his title.[61] Kramnik also
made ambiguous comments about the value of Anand’s title, but did not claim the
title himself.[62] Subsequent world championship matches returned to the format
of a match between the champion and a challenger.The following two championships had special clauses arising from the 2006
unification. Kramnik was given the right to challenge for the title he lost in a
tournament in the World Chess Championship 2008, which Anand won. Then Topalov,
who as the loser of the 2006 match was excluded from the 2007 championship, was
seeded directly into the Candidates final of the World Chess Championship 2010.
He won the Candidates (against Gata Kamsky). Anand again won the championship
match.[63][64]The next championship, the World Chess Championship 2012, had short knock-out
matches for the Candidates Tournament. This format was not popular with
everyone, and world No. 1 Magnus Carlsen withdrew in protest. Boris Gelfand won
the Candidates. Anand won the championship match again, in tie breaking rapid
games, for his fourth consecutive world championship win.[65]

i031Alexander_Khalifmani031 i031Alexander_Khalifman

Split title (1993–2005)

Alexander Khalifman, FIDE World Champion 1999-2000.
Ruslan Ponomariov, FIDE World Champion 2002-2004.
Rustam Kasimdzhanov, FIDE World Champion 2004-2005.
Veselin Topalov, FIDE World Champion 2005-2006.
Reunified title (2006)

1993, Nigel Short broke the domination of Kasparov and Karpov by defeating
Karpov
in the candidates semi-finals followed by Jan Timman in the finals,
thereby earning the right to challenge Kasparov for the title.

However, before
the match took place, both Kasparov and Short complained of corruption and a
lack of professionalism within FIDE
in organizing the match, and
split from FIDE to set up
the Professional Chess Association PCA, under whose auspices they
held their match. In response, FIDE stripped Kasparov of his title and held a
championship match between Karpov and Timman. Kasparov defeated Short while
Karpov beat Timman, and for the first time in history there were two World Chess
Champions
.

FIDE and the PCA each held a championship cycle in 1993–1996, with many of the
same challengers playing in both. Kasparov and Karpov both won their respective
cycles. In the PCA cycle, Kasparov defeated Viswanathan Anand in the PCA World
Chess Championship 1995. Karpov defeated Gata Kamsky in the final of the FIDE
World Chess Championship 1996. Negotiations were held for a reunification match
between Kasparov and Karpov in 1996–97,[59] but nothing came of them.[60]

Soon after the 1995 championship, the PCA folded, and Kasparov had no
organisation to choose his next challenger. In 1998 he formed the World Chess
Council, which organised a candidates match between Alexei Shirov and Vladimir
Kramnik. Shirov won the match, but negotiations for a Kasparov–Shirov match
broke down, and Shirov was subsequently omitted from negotiations, much to his
disgust. Plans for a 1999 or 2000 Kasparov–Anand match also broke down, and
Kasparov organised a match with Kramnik in late 2000. In a major upset, Kramnik
won the match with two wins, thirteen draws, and no losses. At the time the
championship was called the Braingames World Chess Championship, but Kramnik
later referred to himself as the Classical World Chess Champion.

Meanwhile, FIDE had decided to scrap the Interzonal and Candidates system,
instead having a large knockout event in which a large number of players
contested short matches against each other over just a few weeks (see FIDE World
Chess Championship 1998). Rapid and blitz games were used to resolve ties at the
end of each round, a format which some felt did not necessarily recognize the
highest quality play: Kasparov refused to participate in these events, as did
Kramnik after he won the Classical title in 2000. In the first of these events
in 1998, champion Karpov was seeded straight into the final, but subsequently
the champion had to qualify like other players. Karpov defended his title in the
first of these championships in 1998, but resigned his title in protest at the
new rules in 1999. Alexander Khalifman won the FIDE World Championship in 1999,
Anand in 2000, Ruslan Ponomariov in 2002, and Rustam Kasimdzhanov in 2004.

By 2002, not only were there two rival champions, but Kasparov’s strong results
– he had the top Elo rating in the world and had won a string of major
tournaments after losing his title in 2000 – ensured even more confusion over
who was World Champion. In May 2002, American grandmaster Yasser Seirawan led
the organisation of the so-called “Prague Agreement” to reunite the world
championship. Kramnik had organised a candidates tournament (won later in 2002
by Peter Leko) to choose his challenger. It was decided that Kasparov play the
FIDE champion (Ponomariov) for the FIDE title, and the winner of this match play
the winner of the Kramnik–Leko match for a unified title. However, the matches
proved difficult to finance and organise. The Kramnik–Leko match did not take
place until late 2004 (it was drawn, so Kramnik retained his title). Meanwhile,
FIDE never managed to organise a Kasparov match, either with 2002 FIDE champion
Ponomariov, or 2004 FIDE champion Kasimdzhanov. Partly due to his frustration at
the situation, Kasparov retired from chess in 2005, still ranked No. 1 in the
world.

Soon after, FIDE dropped the short knockout format for a World Championship and
announced the FIDE World Chess Championship 2005, a double round robin
tournament to be held in San Luis, Argentina between eight of the leading
players in the world. However Kramnik insisted that his title be decided in a
match, and declined to participate. The tournament was convincingly won by the
Bulgarian Veselin Topalov, and negotiations began for a Kramnik–Topalov match to
unify the title.

i032RPonomariovi032 i032 Ponomariov
i033Kasimdhzanov_Torino_2006i033 i033 Kasimdhzanov_Torino_2006
i034Veselin_Topalov_2013i034 i034
Bulgarian
Veselin_Topalov_2013

Memory and Chess


http://www.chessmaniac.com/memory-and-chess/

Emanuel Lasker stated that anyone this side of an imbecile could become a
master.

In 1894, Alfred Binet conducted one of the first psychological studies
into chess. He found that only chess masters were able to play chess
successfully without seeing the board. In 1927, Soviet psychologists conducted
extensive tests on top chess masters and came to the conclusion that their
powers of memory were only greater than that of the layman as far as chess was
concerned; in other areas of memory, there was no discernible superiority of a
chess master and a layman. In the 1940s, Edward Lasker wrote on an organized
study that was made of a dozen leading chess masters by a group of
psychologists. It was found that a chess master’s memory was only exceptional
where positions on the chessboard were concerned.  In 1965, Adrian de Groot
(1914-2006) published his book “Thought and Choice in Chess”. He found that
visual memory and visual perception were important attributes and that
problem-solving ability was of paramount importance. Memory was particularly
important.

In 1973, William Chase (1940-1983) and Herbert Simon (1916-2001) showed
superior memory for chess positions by chess experts through “chunking”. A chunk
is a pattern or a collection of elements that are strongly associated with one
another, but are weakly associated with elements in other chunks. Chunking the
numbers becomes 1492 10000 64 or when Columbus sailed to America,  zip code
of Zagreb and the number of squares on a chessboard. For chess, a chunk might be
a king-side castling position Kg1, Rf1, Pf2, Pg2, Ph2, Nf3 6 chessmen on 6 out
of 64 squares. Another example is the opening position out of a Ruy Lopez or
Sicilian, Najdorf.

If you had a random position of a bunch of chessmen, a chess player would not
have any more advantage than a non-chess player in recreating the position.

You store chunks in long-term memory (LTM), but you process them through
short-term memory (STM). Adults are able to store 3-7 chunks in short-term or
working memory at any one time in about one minute. If all you can store is 3
chunks, then to visualize the entire chess board and hold it in working memory,
you need to see the entire position in only 3 chunks at most. Therefore, chunks
need to be quite large. You may be able to work with three chunks at any one
time and process information rapidly between your short term memory and your
long term memory in order to visualize the entire board.

In 1987-88, all students in a rural Pennsylvania 6th grade class were
required to participate in chess lessons. None of the pupils had previously
played chess. After a year, the pupils significantly improved in both memory and
verbal reasoning. The program was called ‘Development of Reasoning and Memory
through Chess.’

In 2001, researchers wrote in Nature magazine that a chess grandmaster
studies and practices for at least 10 years to learn more than 100,000 chess
patterns (memory chunks). Consequently, GMs can ‘recognize’ they key elements in
a problem situation much more rapidly than amateurs.

Alekhine had a photographic memory (also known as eidetic memory) as a boy.
In 1925, Alexander Alekhine was given a few standard memory tests. They revealed
that if a test had nothing to do with chess, such as memorizing words, shapes,
or objects, he did no better than an average person. On the other hand, when a
test involved memory of a chess position placed on a board in front of him, he
performed exceptionally well. Several articles have been written on Alekhine
stating that he was able to remember all the master chess games during the last
25-30 years.

Vishy Anand’s mother says that he has always had a photographic memory. He
said the first skill needed is to develop memory hooks. Thanks to all these
hooks, it is easy to remember these games years later  :

  1. You learn a few mates and a few tricks
  2. Then you slowly progress, seeing the games of the great players, classic
    examples that every chess player must know. The  great player explains his
    game, and the key moments
  3. A lot of games are accompanied with diagrams of key positions where
    something interesting happened

Blackburne had a good memory and could memorize large lists of information
and recalled a large number of chess games played by masters. When author
Anderson Graham was looking over some of Blackburne’s chess games with him in
the late 1890s, he was astounded to find that Blackburne could recall chess
games he had not seen for 30 or more years.

Capablanca said he had a photographic memory as a child. He could read seven
pages of history and recite them verbatim. As he got older, Capablanca said he
could hardly remember any of his games he played in the past, but had met
experts who remembered every one of his serious games in the last 22 years.

Magnus Carlsen, in an interview on 60 Minutes, said that he has memorized
10,000 chess games. When he was 2 year old, he was able to recite all the major
car brands of Norway. At age 5, he memorized all the world’s countries, their
flags, and their capitals. He was asked if he had a great memory with other
things other than chess. Carlsen responded, “No, I forget all kinds of stuff. I
mean, I’m pretty good at remembering names, but I can never remember faces. I
regularly lose my credit cards, my mobile phone, keys and so on.”

Bobby Fischer’s memory for chess was pretty good. At the conclusion of the
unofficial Blitz Championship of the World at Hercegnovi, Yugoslavia, in 1970,
Fischer rattled off the scores of all his twenty-two games, involving more than
1,000 moves, from memory. And just prior to his historic match with Taimanov, in
Vancouver, British Columbia, Fischer met the Russian player Vasiukov and showed
him a speed game that the two had played in Moscow fifteen years before. Fischer
recalled the game move by move. Gudmundur Thorarinsson, the organizer of the
1972 world championship match between Fischer and Spassky, recounts a story of
Bobby phoning Icelandic grandmaster Fridrik Olafsson to ask for some technical
advice ahead of the match in 1972. The phone was answered by the Olafsson’s
10-year-old daughter who spouted several sentences of Icelandic that baffled
Fischer. The next day Fischer, who spoke no Icelandic, repeated those sentences
exactly to Thorarinsson, every phrase, every inflection accurate, so that
Thorarinsson could understand precisely what the young girl had said.
Thorarinsson called it a “phonetic memory.”

Garry Kasparov says that he was able to remember all the master games he has
played. In 1987-88, the German magazine Der Spiegel went to considerable effort
and expense to find out Kasparov’s IQ and test his memory. Under the supervision
of an international team of psychologists, Kasparov was given a large battery of
tests designed to measure his memory, spatial ability, and abstract reasoning.
They measured his IQ as 135 and his memory as one of the very best. Kasparov was
asked if he had to re-evaluate the positions on each board every time he had
returned to make a move in a simul, or if he remembered the positions all the
time. Kasparov replied that he in fact remembered all the positions. He also
said he could recall the moves of all the games he had played in the past 6
months.

George Koltanowski had a powerful memory that allowed him to play a large
number of blindfold games simultaneously. He claimed he had a “phonographic
memory” (a keen memory for sequences) that allowed him to do a blindfold
knight’s tour. In the early 1980s, George Koltanowski conducted a blindfold
knight’s tour at the Dayton Chess Club, where I (ChessManiac) was President. A
month later, I wrote a letter to George, and, in fun, asked him what was on c4.
When he got the letter, he phoned me up and was able to recall what was on all
the chess squares (c4 was my name). One time at his apartment, I asked George
Koltanowski’s wife, Leah, if George had a good memory about anything else. She
replied, “George can go to the supermarket and forget his loaf of bread.”

Boris Kostic had a good memory and could recall a large number of master
games.
Irina Krush says she knows people that remember hundreds of games,
but she says she does not have that talent. She says that she remembers her
games from a tournament, but will forget them in a few days. She only remembers
a general shape, a pattern of every game, but not the details.

Emanuel Lasker wrote this about memory. “Chess must not be memorized, simply
because it is not important enough. If you load your memory, you should know
why. Memory is too valuable to be stocked with trifles. Of my fifty-seven years
I have applied at least thirty to forgetting what I had learned or read, and
since I succeeded in this I have acquired a certain ease and cheer which I
should never again like to be without. If need be, I can increase my skill in
Chess, if need be I can do that of which I have no idea at present. I have
stored little in my memory, but I can apply that little, and it is of good use
in many and varied emergencies. I keep it in order, but resist every attempt to
increase its dead weight.”

Frank Marshall had a good memory. In January 1922, Frank Marshall played 155
opponents on Montreal. He won 126, lost 8, and drew 21 (88%) after 7 hours of
play. A week later, he was able to replay 153 of 155 games from memory. What
bothered him was forgetting the other two games. He thought he was losing his
memory.

Many articles about Paul Morphy report that he was able to recite from memory
nearly the entire Civil Code of Louisiana (3,500 articles).

Armenian International Master Ashot Nadanian once mentioned that he can
easily recall chess games some 20 years ago, but cannot remember his mobile
phone number

Miguel Najdorf possessed a strong chess memory. He was able to play a large
number of blindfold simultaneous games.

When Philidor played two blindfold games at once in 1783, it was written up
as one of the greatest memory skills ever displayed. A newspaper wrote, “This
brief article is the record of more than sport and fashion: it is a phenomenon
in the history of man so should be hoarded among the best samples of human
memory, till memory shall be no more.

Harry Nelson Pillsbury had a good memory, being able to play
15 games of chess and 15 games of checkers at the same time, blindfolded, while
also playing cards and memorizing a list of complicated words. His obituary in
the New York Times stated that he died from an “illness contracted through
overexertion (overeffort) of his memory cells.” He actually died of syphilis.

Grandmaster Lev Psakhis was able to remember every one of Bobby Fischer’s
games by heart. In 1973, Grandmaster Salo Flohr brought some Chess Informants
with him during a simultaneous exhibition in Krasnoyarsk, USSR. 14-year-old
Psakhis astounded Flohr by telling him in each diagram who the players were.
Psakhis had memorized every diagram in the book. Psakhis was asked if he was a
prodigy (gifted or intelligent (young) person, sign of something about to
happen, example of a particular quality). Psakhis replied, “No, I just have a
good memory,”

Richard Reti had a strong chess memory, but in other areas, his memory wasn’t
so good. In 1925 Reti played 29 opponents blindfold simultaneously in Sao Paulo
and was able to recall all the games. After the exhibition, he was going home
and forgot his suitcase. When somebody reminded him about it, Reti said, “Thank
you very much. My memory is so bad…”

Akiba Rubinstein was said to know every chess game he played by heart, though
unsubstantiated (Unsupported by other evidence).

Bernard Zukerman has a very good chess memory, which made him one of the
outstanding openings expert.

15. ASP.NET Core 5 – CRUD Using Blazor And Entity Framework Core

Ankit Sharma, 2020.05.28 Updated to .NET Core 3.2 Preview-1
Tutorial: https://www.c-sharpcorner.com/article/asp-net-core-crud-using-blazor-and-entity-framework-core/

Github: https://github.com/AnkitSharma-007/ASPCore.BlazorCrud

Deploy on IIS : https://www.c-sharpcorner.com/article/deploying-a-blazor-application-on-iis/

 

Employee CRUD module (app.)

(Record Management System)

Open MS SQL Server Management studio (tool simmilar to Oracle SQLDeveloper or PHPMyadmin) and create tblEmployee table (catalog) in eg WizLib DB. Connect params are :
Server type:     DB engine
Server name :  localhost\SQLEXPRESS
Auth : Win auth
User name :  SSPC2/ss

Create table tblEmployee( 
  EmployeeId int IDENTITY(1,1) NOT NULL, 
  Name varchar(20) NOT NULL, 
  City varchar(20) NOT NULL, 
  Department varchar(20) NOT NULL, 
  Gender varchar(6) NOT NULL 
)

STEP 1. same as in Calculator example (L:\3_sw_video\net_core\BlazorDemoCalc_AnkitSharma202005.html).

Be aware: Sharma’s tutorials are older than his Github code (.sln) which is in this article !

3 project files (in corresponding 3 dirs) created inside solution dir BlazorCrudEMP : see J:\netcore\source\repos\BlazorCrudEMP\BlazorCrud.sln

  1. BlazorCrud.Client – It has the client-side code and contains the pages that will be rendered on the browser.
  2. BlazorCrud.Server – It has the server-side codes such as DB related operations and web API.
  3. BlazorCrud.Shared – It contains the shared code that can be accessed by both client and server.

Execute the program – click F5 or on IIS while on client proj. – displays navig.menu links Home and Fetch Employees.
No more M, V and C dirs !

Original Counter and Fetch Data pages created automaticaly we deleted.

 

STEP 2. Adding Model to App

  1. Right-click on BlazorCrud.Shared project and then select Add >> New Folder and name the folder as Models. We will be adding our model class in this folder only.
  2. Right-click on Models folder and select Add >> Class. Name your class Employee. This class will contain our Employee model properties.
  3. Open Employee.cs
    J:\netcore\source\repos\BlazorCrudEMP\BlazorCrud\Shared\Models\Employee.cs and put the following code in it :
// J:\netcore\source\repos\BlazorCrudEMP\BlazorCrud\Shared\Models\Employee.cs
using System.ComponentModel.DataAnnotations;

namespace BlazorCrud.Shared.Models
{
    public class Employee
    {
        public int EmployeeId { get; set; }
        [Required]
        public string Name { get; set; }
        [Required]
        public string Gender { get; set; }
        [Required]
        public string Department { get; set; }
        [Required]
        public string City { get; set; }
    }
}

 

STEP 3. Creating DAL for App

DAL is Data Access Layer, here connect string and adapter CRUD functions for calling CRUD fns of lower level.

Right click on Models folder in BlazorCrud.Shared project  and select Add >> Class. Name your class EmployeeContext. This is our Entity Framework DB context class to interact with database. Open EmployeeContext.cs and put the following code into it.

using BlazorCrud.Shared.Models;
// J:\netcore\source\repos\BlazorCrudEMP\BlazorCrud\Shared\Models\EmployeeContext.cs
using Microsoft.EntityFrameworkCore;

namespace BlazorCrud.Server.DataAccess
{
    public class EmployeeContext : DbContext
    {
        public virtual DbSet<Employee> tblEmployee { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            if (!optionsBuilder.IsConfigured)
            {
                //"ora7": "User Id=hr;Password=hr; Data Source=sspc2:1521/XE;"
                //optionsBuilder.UseSqlServer(@"Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=myTestDB;Data Source=ANKIT-LENOVO\SQLEXPRESS;");
                optionsBuilder.UseSqlServer(@"Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=WizLib;Data Source=localhost\SQLEXPRESS;");
            }
        }
    }
}

Do not forget to put your own connection string.

Right click on BlazorCrud.Server project and then select Add >> New Folder and name the folder DataAccess. We will be adding our classes to handle database related operations inside this folder only. Add class to DataAccess folder and name it as EmployeeDataAccessLayer.

// J:\netcore\source\repos\BlazorCrudEMP\BlazorCrud\Server\DataAccess\EmployeeDataAccessLayer.cs
// This class will handle our CRUD related DB operations
using BlazorCrud.Server.Interfaces;
using BlazorCrud.Shared.Models;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace BlazorCrud.Server.DataAccess
{
    public class EmployeeDataAccessLayer: IEmployee
    {
        EmployeeContext db = new EmployeeContext();

        //To Get all employees details   
        public IEnumerable<Employee> GetAllEmployees()
        {
            try
            {
                return db.tblEmployee.ToList();
            }
            catch
            {
                throw;
            }
        }

        //To Add new employee record     
        public void AddEmployee(Employee employee)
        {
            try
            {
                db.tblEmployee.Add(employee);
                db.SaveChanges();
            }
            catch
            {
                throw;
            }
        }

        //To Update the records of a particluar employee    
        public void UpdateEmployee(Employee employee)
        {
            try
            {
                db.Entry(employee).State = EntityState.Modified;
                db.SaveChanges();
            }
            catch
            {
                throw;
            }
        }

        //Get the details of a particular employee    
        public Employee GetEmployeeData(int id)
        {
            try
            {
                Employee employee = db.tblEmployee.Find(id);
                return employee;
            }
            catch
            {
                throw;
            }
        }

        //To Delete the record of a particular employee    
        public void DeleteEmployee(int id)
        {
            try
            {
                Employee emp = db.tblEmployee.Find(id);
                db.tblEmployee.Remove(emp);
                db.SaveChanges();
            }
            catch
            {
                throw;
            }
        }
    }
}

And hence our data access layer is complete.

 

 

Now, we will proceed to create our web API Controller.

STEP 4. Adding web API Controller to App

Right click on BlazorCrud.Server/Controllers folder and select Add >> New Item. An “Add New Item” dialog box will open. Select ASP.NET from the left panel, then select “API Controller Class” from templates panel and put the name as EmployeeController. Press OK.

EmployeeController class calls methods of EmployeeDataAccessLayer class and pass on data to client side.

// J:\netcore\source\repos\BlazorCrudEMP\BlazorCrud\Server\Controllers\EmployeeController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using BlazorCrud.Server.Interfaces;
using BlazorCrud.Shared.Models;
using Microsoft.AspNetCore.Mvc;

// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860

namespace BlazorCrud.Server.Controllers
{
    [Route("api/[controller]")]
    public class EmployeeController : Controller
    {
        private readonly IEmployee objemployee;

        public EmployeeController(IEmployee _objemployee)
        {
            objemployee = _objemployee;
        }

        [HttpGet]
        [Route("Index")]
        public IEnumerable<Employee> Index()
        {
            return objemployee.GetAllEmployees();
        }

        [HttpPost]
        [Route("Create")]
        public void Create([FromBody] Employee employee)
        {
            if (ModelState.IsValid)
                objemployee.AddEmployee(employee);
        }

        [HttpGet]
        [Route("Details/{id}")]
        public Employee Details(int id)
        {

            return objemployee.GetEmployeeData(id);
        }

        [HttpPut]
        [Route("Edit")]
        public void Edit([FromBody]Employee employee)
        {
            if (ModelState.IsValid)
                objemployee.UpdateEmployee(employee);
        }

        [HttpDelete]
        [Route("Delete/{id}")]
        public void Delete(int id)
        {
            objemployee.DeleteEmployee(id);
        }
    }
}

We are done with our backend logic. So, we will now proceed to code our client side.

 

STEP 5. Adding Razor Views to App

Right click on BlazorCrud.Client/Pages folder and then select Add >> New Item. An “Add New Item” dialog box will open, select Web from the left panel, then select “Razor View” from templates panel and name it FetchEmployee.cshtml.

This will add a FetchEmployee.cshtml page to our BlazorCrud.Client/Pages folder. Similarly add 3 more pages AddEmployee.cshtml, EditEmployee.cshtml and DeleteEmployee.cshtml.

Let’s add codes to these pages

5.1 V FetchEmployee.razor (was .cshtml)

This page will be displaying all the employee records present in the database. Additionally, we will also provide action methods Edit and Delete on each record. Open FetchEmployee.cshtml and put the following code in it.

@* J:\netcore\source\repos\BlazorCrudEMP\BlazorCrud\Client\Pages\FetchEmployee.razor *@
@page "/fetchemployee"
@using BlazorCrud.Shared.Models
@inject HttpClient Http


<h1>Employee Data</h1>
<p>This component demonstrates fetching Employee data from the server.</p>

<p>
    <a href="/addemployee">Create New</a>
</p>

@if (empList == null)
{
<p><em>Loading...</em></p> }
            else
            {
<table class='table'>
    <thead>
        <tr>
            <th>ID</th>
            <th>Name</th>
            <th>Gender</th>
            <th>Department</th>
            <th>City</th>
        </tr>
    </thead>
    <tbody>
        @foreach (var emp in empList)
        {
<tr>
    <td>@emp.EmployeeId</td>
    <td>@emp.Name</td>
    <td>@emp.Gender</td>
    <td>@emp.Department</td>
    <td>@emp.City</td>
    <td>
        <a href='/editemployee/@emp.EmployeeId'>Edit</a>  |
        <a href='/delete/@emp.EmployeeId'>Delete</a>
    </td>
</tr>}
    </tbody>
</table>}


@code { Employee[] empList;

  protected override async Task OnInitializedAsync()
  {
     empList = await Http.GetJsonAsync<Employee[]>("/api/Employee/Index");
  }
}

Let’s understand this code

On the top, we have included Blazor.Shared.Models namespace so that we can use our Employee model class in this page.

We are defining the route of this page using @page directive. So, in this application, if we append “/fetchemployee” to base URL then we will be redirected to this page.

We are also injecting HttpClient service to enable web API call.

Then we have defined the HTML part to display all the employees record in a tabular manner. We have also added two action links for Edit and Delete which will navigate to EditEmployee.cshtml and DeleteEmployee.cshtml pages.

At the bottom of the page, we have a @code (eas functions) section which contains our business logic. We have created an array variable empList of type Employee and populating it inside OnInitAsync method by calling our web API. This will bind to our HTML table on the page load.

 

5.2 V AddEmployee.razor

This page is used to create a new employee record.

@* J:\netcore\source\repos\BlazorCrudEMP\BlazorCrud\Client\Pages\AddEmployee.razor *@
@page "/addemployee"
@using BlazorCrud.Shared.Models
@inject HttpClient Http
@inject NavigationManager urlNavigationManager

<h1>Create Employee</h1>
<hr />

<EditForm Model="@emp" OnValidSubmit="CreateEmployee">
    <DataAnnotationsValidator />
    <div class="form-group row">
        <label class="control-label col-md-12">Name</label>
        <div class="col-md-4">
            <input class="form-control" @bind="emp.Name" />
        </div>
        <ValidationMessage For="@(() => emp.Name)" />
    </div>
    <div class="form-group row">
        <label class="control-label col-md-12">Gender</label>
        <div class="col-md-4">
            <select class="form-control" @bind="emp.Gender">
                <option value="">-- Select Gender --</option>
                <option value="Male">Male</option>
                <option value="Female">Female</option>
            </select>
        </div>
        <ValidationMessage For="@(() => emp.Gender)" />
    </div>
    <div class="form-group row">
        <label class="control-label col-md-12">Department</label>
        <div class="col-md-4">
            <input class="form-control" @bind="emp.Department" />
        </div>
        <ValidationMessage For="@(() => emp.Department)" />
    </div>
    <div class="form-group row">
        <label class="control-label col-md-12">City</label>
        <div class="col-md-4">
            <input class="form-control" @bind="emp.City" />
        </div>
        <ValidationMessage For="@(() => emp.City)" />
    </div>
    <div class="form-group">
        <button type="submit" class="btn btn-primary">Save</button>
        <button class="btn btn-light" @onclick="Cancel">Cancel</button>
    </div>
</EditForm>

@code { Employee emp = new Employee();

   protected async Task CreateEmployee()
   {
      await Http.SendJsonAsync(HttpMethod.Post, "/api/Employee/Create", emp);
      urlNavigationManager.NavigateTo("/fetchemployee");
   }

   void Cancel()
   {
      urlNavigationManager.NavigateTo("/fetchemployee");
   }
 }

In this page the route is “/addemployee”.

We are also injecting urlNavigationManager (was “Microsoft.AspNetCore.Blazor.Services.IUriHelper”) service to enable URL redirection. The HTML part will generate a form to get inputs from the user. The attribute “bind” is used to bind the value entered in the textbox to the properties of Employee object.

In the @code (was functions) section we have defined two methods :

  1.  CreateEmployee will be invoked on clicking “Submit” button and send a POST request to our API along with the Employee object emp.
  2. Cancel method will be invoked on clicking cancel button and redirect the user back to FetchEmployee page.

5.3 V EditEmployee.razor

@* J:\netcore\source\repos\BlazorCrudEMP\BlazorCrud\Client\Pages\EditEmployee.razor *@
@page "/editemployee/{empID:int}"
@using BlazorCrud.Shared.Models
@inject HttpClient Http
@inject NavigationManager urlNavigationManager

<h2>Edit Employee</h2>
<hr />

<EditForm Model="@emp" OnValidSubmit="UpdateEmployee">
    <DataAnnotationsValidator />
    <div class="form-group row">
        <label class="control-label col-md-12">Name</label>
        <div class="col-md-4">
            <input class="form-control" @bind="emp.Name" />
        </div>
        <ValidationMessage For="@(() => emp.Name)" />
    </div>
    <div class="form-group row">
        <label class="control-label col-md-12">Gender</label>
        <div class="col-md-4">
            <select asp-for="Gender" class="form-control" @bind="emp.Gender">
                <option value="">-- Select Gender --</option>
                <option value="Male">Male</option>
                <option value="Female">Female</option>
            </select>
        </div>
        <span><ValidationMessage For="@(() => emp.Gender)" /></span>
    </div>
    <div class="form-group row">
        <label class="control-label col-md-12">Department</label>
        <div class="col-md-4">
            <input class="form-control" @bind="emp.Department" />
        </div>
        <span><ValidationMessage For="@(() => emp.Department)" /></span>
    </div>
    <div class="form-group row">
        <label class="control-label col-md-12">City</label>
        <div class="col-md-4">
            <input class="form-control" @bind="emp.City" />
        </div>
        <span><ValidationMessage For="@(() => emp.City)" /></span>
    </div>
    <div class="form-group">
        <button type="submit" class="btn btn-primary">Save</button>
        <button class="btn btn-light" @onclick="Cancel">Cancel</button>
    </div>
</EditForm>

@code { [Parameter]
    public int empID { get; set; }

    Employee emp = new Employee();

    protected override async Task OnInitializedAsync()
    {
        emp = await Http.GetJsonAsync<Employee>("/api/Employee/Details/" + empID);
    }

    protected async Task UpdateEmployee()
    {
        await Http.SendJsonAsync(HttpMethod.Put, "api/Employee/Edit", emp);
        urlNavigationManager.NavigateTo("/fetchemployee");
    }

    void Cancel()
    {
        urlNavigationManager.NavigateTo("/fetchemployee");
    }
}

In this page we have defined the route as “/editemployee/{empID}”. empID is an URL parameter of type string declared in @code section. We will use the [Parameter] attribute to mark the variable as a parameter. To navigate to this page, we need to pass the employee id in the URL which will be captured in empID variable. If we do not mark the variable with the [Parameter] attribute, we will get an error “Object of type ‘BlazorCrud.Client.Pages.EditEmployee’ has a property matching the name ’empID’, but it does not have [ParameterAttribute] applied.”. This will not allow empID to bind to the employee id value passed in the parameter.

The HTML part is similar to that of AddEmployee.cshtml page. The attribute “bind” is used for two-way binding; i.e., binding edited textbox values to employee object properties and vice versa.

Inside the @code section we are fetching the employee records in OnInitAsync method based on the employeeID passed in the parameter. This will bind to the fields in the form on page load itself.

UpdateEmployee method will send a PUT request to our API along with the Employee object emp. The Cancel method will be invoked on clicking cancel button and redirect the user back to FetchEmployee page.

5.4 V DeleteEmployee.razor

@* J:\netcore\source\repos\BlazorCrudEMP\BlazorCrud\Client\Pages\DeleteEmployee.razor  *@
@page "/delete/{empID:int}"
@using BlazorCrud.Shared.Models
@inject HttpClient Http
@inject NavigationManager urlNavigationManager

<h2>Delete Employee</h2>
<h3>Are you sure you want to delete employee with id : @empID</h3>
<br />

<div class="col-md-4">
    <table class="table">
        <tr>
            <td>Name</td>
            <td>@emp.Name</td>
        </tr>
        <tr>
            <td>Gender</td>
            <td>@emp.Gender</td>
        </tr>
        <tr>
            <td>Department</td>
            <td>@emp.Department</td>
        </tr>
        <tr>
            <td>City</td>
            <td>@emp.City</td>
        </tr>
    </table>
    <div class="form-group">
        <button class="btn btn-danger" @onclick="(async () => await Delete())">Delete</button>
        <button class="btn btn-light" @onclick="Cancel">Cancel</button>
    </div>
</div>

@code { [Parameter]
    public int empID { get; set; }

    Employee emp = new Employee();

    protected override async Task OnInitializedAsync()
    {
        emp = await Http.GetJsonAsync<Employee>("/api/Employee/Details/" + empID);
    }

    protected async Task Delete()
    {
        await Http.DeleteAsync("api/Employee/Delete/" + Convert.ToInt32(empID));
        urlNavigationManager.NavigateTo("/fetchemployee");
    }

    void Cancel()
    {
        urlNavigationManager.NavigateTo("/fetchemployee");
    }
}

The route for this page is also parametrized since we are fetching the record of the employee on page load.

The HTML part will display the employee data and ask the user for a confirmation to delete the employee record.

Inside the @code section we are fetching the employee records in OnInitAsync method based on the employeeID passed in the parameter. This will display the employee records as the page loads.

The Delete method will be invoked on clicking “Delete” button, which will send a delete request to our API along with the employee ID of the employee to be deleted. On successful deletion the user will be navigated back to FetchEmployee page.

Navigation menu for our module (app.)

Open BlazorCrud.Client/Shared/ NavMenu.razor file and put the following code in it.

@* J:\netcore\source\repos\BlazorCrudEMP\BlazorCrud\Client\Shared\NavMenu.razor *@
<div class="top-row pl-4 navbar navbar-dark">
    <a class="navbar-brand" href="">BlazorCrud</a>
    <button class="navbar-toggler" @onclick="ToggleNavMenu">
        <span class="navbar-toggler-icon"></span>
    </button>
</div>

<div class="@NavMenuCssClass" @onclick="ToggleNavMenu">
    <ul class="nav flex-column">

        <li class="nav-item px-3">
            <NavLink class="nav-link" href="" Match="NavLinkMatch.All">
                <span class="oi oi-home" aria-hidden="true"></span> Home
            </NavLink>
        </li>

        <li class="nav-item px-3">
            <NavLink class="nav-link" href="fetchemployee">
                <span class="oi oi-list-rich" aria-hidden="true"></span> Fetch employee
            </NavLink>
        </li>

    </ul>
</div>

@code { private bool collapseNavMenu = true;

    private string NavMenuCssClass => collapseNavMenu ? "collapse" : null;

    private void ToggleNavMenu()
    {
        collapseNavMenu = !collapseNavMenu;
    }
}

 

URL R : https://localhost:5001/fetchemployee – URL has “/fetchemployee” appended to it as we have defined it using @page directive.

URL C : https://localhost:5001/addemployee

URL U and D : https://localhost:5001/editemployee/2 – simmilar to releteemployee/2

 

 

WPF :

https://www.youtube.com/watch?v=LUKp76CNmJY         https://goo.gl/Axoeja

https://www.youtube.com/watch?v=NiGsgctfiYM           https://goo.gl/fAUCRh

 

14. ASP.NET CORE 5 : Blazor Getting Started : Calculator module

Ankit Sharma, 2020.05.28 Updated to .NET Core 3.2 Preview-1

Tutorial: https://www.c-sharpcorner.com/article/getting-started-with-blazor/

Github: https://github.com/AnkitSharma-007/ASPCore.BlazorDemo

Calculator module using Blazor

Prerequisites
  • Install .NET Core  SDK from here  or SDK preview
  • Install Visual Studio Community 2019  Latest with the ASP.NET and web development workload selected from here or preview
  • Entity Framework Core Tools >> NuGet or on command-line tools: dotnet tool install –global dotnet-ef
    (Install ASP.NET Core Blazor Language Services extension from here not needed (needed in VS2019) older ?))
  • SQL Server 2012 or above

STEP 1. 

  1. VS2019 >> File >> New >> Project
  2. Select Blazor App C# (older : .NET Core inside Visual C# menu from the left panel)
  3. Select Blazor App (older : “ASP.NET Core Web Application”) from available project types.
  4. Put the name of the project as BlazorDemoCalc and J:\netcore\source\repos
  5. Click “Blazor WebAssembly App”, “ASP.NET Core hosted”, “Progressive web app”

 

STEP 2. Client proj, Pages folder. We will be adding our view pages to this folder only. These pages will be rendered on the web.

Execute the program – displays navigation links Home, Counter, Fetch data in navigation menu are displayed.

  1. Right click on Pages folder in Client proj >> select Add >> New Item
  2.  “Add New Item” dialog box will open. Selected is Visual C# from the left panel (old : select Web) ,
  3. select Razor Component from templates panel and put the name as Calculator (old : Razor View – empty)

J:\netcore\source\repos\BlazorDemoCalc\BlazorDemo\Pages\Calculator.razor

@page "/calculator"

<h1>Basic Calculator Demo Using Blazor</h1>
<hr />
<div>
    <div class="row">
        <div class="col-md-3">
            <p>First Number</p>
        </div>
        <div class="col-md-4">
            <input placeholder="Enter First Number" @bind="@num1" />
        </div>
    </div>
    <br />
    <div class="row">
        <div class="col-md-3">
            <p>Second Number</p>
        </div>
        <div class="col-md-4">
            <input placeholder="Enter Second Number" @bind="@num2" />
        </div>
    </div>
    <br />
    <div class="row">
        <div class="col-md-3">
            <p>Result</p>
        </div>
        <div class="col-md-4">
            <input readonly @bind="@finalresult" />
        </div>
    </div>
    
    <br />
    <div class="row">
        <div class="col-md-2">
            <button @onclick="AddNumbers" class="btn btn-light">Add (+)</button>
        </div>
        <div class="col-md-2">
            <button @onclick="SubtractNumbers" class="btn btn-primary">Subtract (−)</button>
        </div>
        <div class="col-md-2">
            <button @onclick="MultiplyNumbers" class="btn btn-success ">Multiply (X)</button>
        </div>
        <div class="col-md-2">
            <button @onclick="DivideNumbers" class="btn btn-info">Divide (/)</button>
        </div>
    </div>
</div>

@code {
    string num1;
    string num2;
    string finalresult;
    void AddNumbers()
    {
        finalresult = (Convert.ToDouble(num1) + Convert.ToDouble(num2)).ToString();
    }
    void SubtractNumbers()
    {
        finalresult = (Convert.ToDouble(num1) - Convert.ToDouble(num2)).ToString();
    }
    void MultiplyNumbers()
    {
        finalresult = (Convert.ToDouble(num1) * Convert.ToDouble(num2)).ToString();
    }
    void DivideNumbers()
    {
        if (Convert.ToDouble(num2) != 0)
        {
            finalresult = (Convert.ToDouble(num1) / Convert.ToDouble(num2)).ToString();
        }
        else
        {
            finalresult = "Cannot Divide by Zero";
        }
    }
}

Let’s understand Calculator.razor

On the top, we are defining the route of this page using @page directive. So in this module, if we append “/calculator” to base URL then we will be redirected to this page.

Then we have defined the HTML section to read two numbers from the user and display the result in another textbox. The attribute “bind is used to bind the value entered in the textbox to the variables we have defined. We also created four buttons to perform our basic arithmetic operations. We are calling our business logic methods on button click.

At the bottom of the page, we have a @code (was functions) section which contains all our business logic. We have declared three variables, two variables to read the value from the user and another one to display the result. We have also defined four methods to handle addition, subtraction, multiplication, and division. The “bind” attribute will work only for string variables not for floating point values. Hence, we need to convert a string to double to perform our arithmetic operations.

 

 

STEP 3.  Add the link to our “calculator” page in the navigation menu, open /Shared/NavMenu.razor page

J:\netcore\source\repos\BlazorDemoCalc\BlazorDemo\Shared\NavMenu.razor

and put the following BLUE COLORED code into it.

<div class="top-row pl-4 navbar navbar-dark">
    <a class="navbar-brand" href="">BlazorDemoCalcDev</a>
    <button class="navbar-toggler" @onclick="ToggleNavMenu">
        <span class="navbar-toggler-icon"></span>
    </button>
</div>

<div class="@NavMenuCssClass" @onclick="ToggleNavMenu">
    <ul class="nav flex-column">
        <li class="nav-item px-3">
            <NavLink class="nav-link" href="" Match="NavLinkMatch.All">
                <span class="oi oi-home" aria-hidden="true"></span> Home
            </NavLink>
        </li>
        <li class="nav-item px-3">
            <NavLink class="nav-link" href="counter">
                <span class="oi oi-plus" aria-hidden="true"></span> Counter
            </NavLink>
        </li>
        <li class="nav-item px-3">
            <NavLink class="nav-link" href="fetchdata">
                <span class="oi oi-list-rich" aria-hidden="true"></span> Fetch data
            </NavLink>
        </li>

        <li class="nav-item px-3">
            <NavLink class="nav-link" href="calculator">
                <span class="oi oi-plus" aria-hidden="true"></span> Calculator
            </NavLink>
        </li>
    </ul>
</div>

@code {
    private bool collapseNavMenu = true;

    private string NavMenuCssClass => collapseNavMenu ? "collapse" : null;

    private void ToggleNavMenu()
    {
        collapseNavMenu = !collapseNavMenu;
    }
}

 

What is Blazor

Blazor framework is not supported by versions below Visual Studio 2017 v15.7. Microsoft defined Blazor as an experimental project and it was in alpha phase as of March 30, 2018. Blazor is new free, open source .NET Web framework for creating client-side applications using C# / Razor and HTML that runs in the browser with WebAssembly, see http://webassembly.org/

What is WebAssembly

WebAssembly (abbreviated Wasm) is low-level assembly-like language with a compact binary format that can run in modern web browser. Since it is a low-level binary code, it cannot be read/written by humans but we can compile the code from other languages to WebAssembly to facilitate their execution on the browser. It is a subset of JavaScript and is designed to complement and run alongside JavaScript. It enables us to run code written in multiple language on the web at near native speed.
WebAssembly is developed as a web standard and is supported by all the major browsers without plugins.

Why use Blazor

Blazor makes web development easier and more productive by providing a full stack web development with .NET. It runs in all browsers on the real .NET runtime and have full support for .NET Standard without the need of any extra plugin. Blazor is fast, have reusable components and is open-source with a great support from the community.
Blazor also supports features of a SPA framework such as:
  • Routing
  • Layouts
  • Forms and validation
  • JavaScript interop
  • Build on save during development
  • Server-side rendering
  • Dependency Injection

Using .NET for developing Client-side application has multiple advantages :

  1. .NET offers a range of API and tools across all platform that are stable and easy to use.
  2. The modern languages such as C# and F# offer a lot of features that make programming easier and interesting for developers.
  3. The availability of one of the best IDE in form of Visual Studio provides a great .NET development experience across multiple platforms such as Windows, Linux, and MacOS.
  4. .NET provides features such as speed, performance, security, scalability, and reliability in web development that makes full stack development easier.

 

 

See Fluxor https://github.com/mrpmorris/fluxor

https://medium.com/pipelinespace/setting-up-a-ci-cd-pipeline-in-azure-devops-for-blazor-and-deploy-to-azure-c262c58d8172

 

13. PHP 7.4.2, Bootstrap 4.3.1 : Laravel 6.12 CRUD tutorial

2020.02.17 Tested on newest Windows 10 64 bit, XAMPP – works !

http://localhost:8083/laravel6/public/shows/create
http://localhost:8083/laravel6/public/shows/ – here are del and edit buttons
http://localhost:8083/laravel6/public/shows/1/edit

https://appdividend.com/2019/09/12/laravel-6-crud-example-laravel-6-tutorial-for-beginners/ 2019.12.10 by Krunal

https://github.com/KrunalLathiya/Laravel6CRUDExample

http://dev1:8083/fwphp/glomodul/blog/?i/read_post/id/43#crequest is URL to show this article in my Blog (Msg module).

 

1. MySQL DB   2. M   3. C requeest   4. Bootstrap 4

5. CreRequest   6. validateSaveResponse

7. RvDisplayresponse   8. CUD   9. D

Install Laravel 6.12

1. MySQL DB   2. M   3. C requeest   4. Bootstrap 4

5. CreRequest   6. validateSaveResponse

7. RvDisplayresponse   8. CUD   9. D

Install Laravel 6.12

For some reason WordPress editor changes pasted text to uppercase !! eg :
composer create-project –prefer-dist laravel/laravel laravel6

~ 130 MB – one of reasons why I do not like such developing SW (included is Oracle Forms). If error – how debug 130 MB ?
B12phpfw has 20-30 kB code to debug (few hundert lines) using own debugging and Xdebug which both work excellent.
If there were somebody who guaranties support (for many years) then huge developing SW would be better. Stories about security… are not true – we only need good help about implement security and some features (which is difficult to find).

cd J:\xampp\htdocs\laravel6\
install the frontend dependencies :

npm install

Step 1. Configure MySQL DB

Values inside .env file are loaded inside the files from the config directory.

J:\xampp\htdocs\laravel6\.env file

Where J:\xampp\htdocs\laravel6\ is root of our laravel project.

If you make changes to .env file then don’t forget to restart server ( if you are using laravel dev server). If you are using virtual host and changes don’t seem to take effect then run :

cd J:\xampp\htdocs\laravel6\

php artisan config:clear

(This command will clear the configuration cache) in your terminal.

Laravel always ships with the migration files, so you can generate DB tables so :

php artisan migrate

migrations table created successfully. Laravel comes with three migrations which are used for authentication. Their file names are prepended with a timestamp :

Migrating: 2014_10_12_000000_create_users_table
Migrated: 2014_10_12_000000_create_users_table (0.48 seconds)
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated: 2014_10_12_100000_create_password_resets_table (0.44 seconds)
Migrating: 2019_08_19_000000_create_failed_jobs_table
Migrated: 2019_08_19_000000_create_failed_jobs_table (0.27 seconds)

select * from information_schema.tables where table_schema = ‘z_laravel6’ and table_name = ‘migrations’ and table_type = ‘BASE TABLE’

Step 2. M – create model and migration files

Database migration is used to save details about DB table, so you don’t have to manually generate all of the tables by going to the database interface or phpmyadmin or …
We can develop migrations using artisan with ‘make: migration’ command.
Type the following command to create a model and migration files.

cd J:\xampp\htdocs\laravel6\

php artisan make:model Show -m

It will create migration files inside database/migrations directory J:\xampp\htdocs\laravel6\database\migrations\ :

  1. J:\xampp\htdocs\laravel6\database\migrations\Show.php file – model name has to be singular
  2. [timestamp]_create_shows_table.php migration file – migration name should be plural to automatically find table name.

//J:\xampp\htdocs\laravel6\database\migrations\2020_02_17_074520_create_shows_table.php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateShowsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     *
     * Create table in DB using the following command.
     *    php artisan migrate
     * execute up() function ee run all migrations and create defined tbls (incremental changes).
     *
     * To reverse the migrations :
     *    php artisan migrate:rollback which will execute the down() function.
     *
     */
    public function up()
    {
        Schema::create('shows', function (Blueprint $table) {
           $table->bigIncrements('id');        //**php artisan make:model Show -m created**
              $table->string('show_name');   //**I added**
              $table->string('genre');
              $table->float('imdb_rating');
              $table->string('lead_actor');
           $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('shows');
    }
}

If you want to create the migration but have a different table name in mind, then you can explicitly define a table name with ‘create‘ flag.

  1. up() function is used for creating/updating tables, columns, and indexes Inside up() function, We have the Schema: create(‘table_name,’ callback) method which will be used for creating the new table.
    1. Inside a callback, we have $table->bigIncrements(‘id’) which will create auto_increment integer column with the primary key and argument ‘id’ is the name of a column.
    2. Second is $table->timestamps() which will create the two timestamp columns created_at and updated_at.
  2. down() function is used for reversing an operation done by up() method
       $table->bigIncrements('id');        //**php artisan make:model Show -m created**       
          $table->string('show_name');   //**I added 4 columns**        
          $table->string('genre');      
          $table->float('imdb_rating');          
          $table->string('lead_actor');            
       $table->timestamps();  //**php artisan make:model Show -m created**          

Create table in DB using the following command :

php artisan migrate

which will execute up() function ee run all migrations and create defined tbls (incremental changes).

To reverse the migrations :

php artisan migrate:rollback

which will execute down() function.

Now, add the fillable property inside file :

J:\xampp\htdocs\laravel6\app\Show.php

// J:\xampp\htdocs\laravel6\app\Show.php
namespace App;
use Illuminate\Database\Eloquent\Model;

/*
* We can specify all the properties to modify the behavior of the model.
* We can write a $table property which is used to determine a name of the table that this model will interact with in the future operations.
* By default, It will define a table name as the plural of the model name, e.g., shows table for Show model and users table for User model.
* When you don't need to use timestamps on your table, then you will also have to specify the $timestamps property and set it to false value in your Model because Laravel expects your table to have the created_at and updated_at timestamp columns.
*/
class Show extends Model
{
   protected $fillable = [
      'show_name', 'genre', 'imdb_rating', 'lead_actor'
   ];
}

Step 3. C – Create routes and controller

First, create the ShowController using the following command.

php artisan make:controller ShowController –resource

Note that we have also added the — resource flag which will define six methods inside the ShowController namely:

  1. Index (used for displaying a list of Shows)
  2. Create (will show the view with a form for creating a Show)
  3. Store (used for creating a Show inside the database. Note: create method submits to store method)
  4. Show (will display a specified Show)
  5. Edit (will show the form for editing a Show. Form will be filled with the existing Show data)
  6. Update (Used for updating a Show inside the database. Note: edit submits to update method)
  7. Destroy (used for deleting a specified Show)

J:\xampp\htdocs\laravel6\routes\web.php

add Route::resource… line of code :

// ShowController.php
Route::get('/', function () {
    return view('welcome');
});

Route::resource('shows', 'ShowController');

We can pass dynamic parameters with {} brackets, and you might have noticed that show, update, and destroy has the same url but different methods, so its legit.

Just like resource flag, laravel has a method called resource() that will generate all the above routes. You can also use that method instead of specifying them individually like above.

Actually, by adding Route::resource… line, we have registered multiple routes for our application. We can check it so :

php artisan route:list

Domain Method URI Name Action Middleware
GET/HEAD / Closure web
GET/HEAD api/user Closure api,auth:api
GET/HEAD shows shows.index App\Http\Controllers\ShowController@index web
POST shows shows.store App\Http\Controllers\ShowController@store web
GET/HEAD shows/create shows.create App\Http\Controllers\ShowController@create web
GET/HEAD shows/{show} shows.show App\Http\Controllers\ShowController@show web
PUT/PATCH shows/{show} shows.update App\Http\Controllers\ShowController@update web
DELETE shows/{show} shows.destroy App\Http\Controllers\ShowController@destroy web
GET/HEAD shows/{show}/edit shows.edit App\Http\Controllers\ShowController@edit web

Step 4. Configure Bootstrap 4

Right now (2019.12.10), there are some issues, or somehow I do not see any code inside the public >> css >> app.css file. I have already compiled the CSS and JS file by the

npm run dev

command, but still, the app.css file is empty.

One possible solution is to copy code of previous version’s Laravel’s app.css file and paste it here :

J:\xampp\htdocs\laravel6\public\css\ap.css

Link of the previous css file is :
https://raw.githubusercontent.com/KrunalLathiya/Laravel58CRUD/master/public/css/app.css

Second possible solution is this. This new scaffolding is only available in Laravel 6 and not in the earlier versions like Laravel 5.8 or 5.7.

While Laravel 6 does not dictate which JavaScript or CSS pre-processors you use, it does provide the essential starting point using Bootstrap and Vue that will be helpful for many projects.

By default, the Laravel uses the NPM to install both of these frontend packages.

Bootstrap and Vue scaffolding provided by Laravel is located in the laravel/ui Composer package, which you can install using Composer so :

composer require laravel/ui –dev

Once laravel/ui package has been installed, and you may install the frontend scaffolding using the ui Artisan command:

// Generate basic scaffolding…
php artisan ui vue
php artisan ui react

// Generate login / registration scaffolding…
php artisan ui vue –auth
php artisan ui react –auth

Step 5. Create request (form to insert show tbl row)

Create the views.

http://localhost:8083/laravel6/public/shows/create

Inside the J:\xampp\htdocs\laravel6\resources\views folder where is only welcome.blade.php , create view files :

  1. C create.blade.php
  2. U edit.blade.php
  3. R index.blade.php Inside the views folder, we also need to create the layout file. So create a file inside the views folder called

    layout.blade.php :

    our main template file, and all the other view files will extend this layout.blade.php file.

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Laravel 6 CRUD Example</title>
    <link href="{{ asset('css/app.css') }}" rel="stylesheet" type="text/css" />
    </head>
    <body>
    <div class="container">
    @yield('content')
    </div>
    <script src="{{ asset('js/app.js') }}" type="text/js"></script>
    </body>
    </html>

    Here, we have already included the Bootstrap 4 by adding the app.css.

create.blade.php :

@extends('layout')

@section('content')
<style>
  .uper {
    margin-top: 40px;
  }
</style>
<div class="card uper">
  <div class="card-header">
    Add Shows
  </div>
  <div class="card-body">
    @if ($errors->any())
      <div class="alert alert-danger">
        <ul>
            @foreach ($errors->all() as $error)
              <li>{{ $error }}</li>
            @endforeach
        </ul>
      </div><br />
    @endif
      <form method="post" action="{{ route('shows.store') }}">
          <div class="form-group">
              @csrf
              <label for="name">Show Name:</label>
              <input type="text" class="form-control" name="show_name"/>
          </div>
          <div class="form-group">
              <label for="price">Show Genre :</label>
              <input type="text" class="form-control" name="genre"/>
          </div>
          <div class="form-group">
              <label for="price">Show IMDB Rating :</label>
              <input type="text" class="form-control" name="imdb_rating"/>
          </div>
          <div class="form-group">
              <label for="quantity">Show Lead Actor :</label>
              <input type="text" class="form-control" name="lead_actor"/>
          </div>
          <button type="submit" class="btn btn-primary">Create Show</button>
      </form>
  </div>
</div>
@endsection

Open ShowController.php file, and on the create() function, we need to return the view, and that is a create.blade.php file.

// ShowController.php

public function create()
{
   return view('create'); // create.blade.php file
}

Go to a http://localhost:8000/books/create or http://laravel6.test/shows/create

http://localhost:8083/laravel6/public/shows/create

You will see form “Create show”.
Add Shows Show Name: Show Genre : Show IMDB Rating : Show Lead Actor : Create show button

Step 6. Add Laravel Validation rules and save data

First step inside the ShowController.php is that import namespace of Show model inside the ShowController.php file.


// ShowController.php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Show; // import namespace of Show model 

Write following code inside ShowController.php file’s store() function.

public function store(Request $request)
{
        $validatedData = $request->validate([
            // check for all four fields of the form
            // If incoming data fail any of the rules, then it will directly go to the form with the error messages
            // $request object parameter will be used to access form data
            'show_name' => 'required|max:255',
            'genre' => 'required|max:255',
            'imdb_rating' => 'required|numeric',
            'lead_actor' => 'required|max:255',
        ]);

        $show = Show::create($validatedData);

        return redirect('/shows')->with('success', 'Show is successfully saved');
 }

The first thing you want to do is validate a form of data.
We can use a $request->validate() function for validation, which will receive the array of validation rules.
Validation rules is an associative array.
Key will be the field_name and value with being the validation rules.

The second parameter is the optional array for custom validation messages.
Rules are separated with pipe sign “|.” We are using the most basic validation rules https://laravel.com/docs/5.8/validation#available-validation-rules .

First is “required,” which means the field_name should not be empty. (“nullable” rule is vice versa), “string” means it should be the string value, “min” is the limit of minimum characters for a string in an input field and “max” is the maximum characters. “unique:table, column” with see if the same value does not exists in the database (comes handy for storing emails or any other unique data).

If the validation fails, then it will redirect us back. After the validation, we are creating a new book and save that book in the database.
We need to loop through that error messages inside the create.blade.php file which we have already done it.

If you leave all the form fields empty, then you will find an error message at page top.

Now, if you fill the form fields correctly, then it will create a new row in the database.

Step 7. V – display response

Display the data.

http://localhost:8083/laravel6/public/shows/

Write the ShowController’s index function to return an index view with data fetched from a database. Write the following code inside the index() function.

// ShowController.php

public function index()
{
     $shows = Show::all();

     return view('index', compact('shows'));
}

Create a file inside the views folder :

index.blade.php

@extends('layout')

@section('content')
<style>
  .uper {
    margin-top: 40px;
  }
</style>
<div class="uper">
  @if(session()->get('success'))
    <div class="alert alert-success">
      {{ session()->get('success') }}  
    </div><br />
  @endif
  <table class="table table-striped">
    <thead>
        <tr>
          <td>ID</td>
          <td>Show Name</td>
          <td>Show Genre</td>
          <td>Show IMDB Rating</td>
          <td>Lead Actor</td>
          <td colspan="2">Action</td>
        </tr>
    </thead>
    <tbody>
        @foreach($shows as $show)
        <tr>
            <td>{{$show->id}}</td>
            <td>{{$show->show_name}}</td>
            <td>{{$show->genre}}</td>
            <td>{{number_format($show->imdb_rating,2)}}</td>
            <td>{{$show->lead_actor}}</td>
            <td><a href="{{ route('shows.edit', $show->id)}}" class="btn btn-primary">Edit</a></td>
            <td>
                <form action="{{ route('shows.destroy', $show->id)}}" method="post">
                  @csrf
                  @method('DELETE')
                  <button class="btn btn-danger" type="submit">Delete</button>
                </form>
            </td>
        </tr>
        @endforeach
    </tbody>
  </table>
<div>
@endsection

We have used the PHP number_format() function to print the IMDB Rating float value.

Here, we have looped through the show’s array and display the data in the table format.

Also, we have added two buttons for edit and delete operation.

Step 8. CUD

Create Edit and Update Operation.
Add following code inside ShowController.php edit function :

// ShowController.php

public function edit($id)
{
     $show = Show::findOrFail($id);

     return view('edit', compact('show'));
}

Create new file inside the views folder

edit.blade.php

@extends('layout')

@section('content')
<style>
  .uper {
    margin-top: 40px;
  }
</style>
<div class="card uper">
  <div class="card-header">
    Update Shows
  </div>
  <div class="card-body">
    @if ($errors->any())
      <div class="alert alert-danger">
        <ul>
            @foreach ($errors->all() as $error)
              <li>{{ $error }}</li>
            @endforeach
        </ul>
      </div><br />
    @endif
    <form method="post" action="{{ route('shows.update', $show->id) }}">
          <div class="form-group">
              @csrf
              @method('PATCH')
              <label for="name">Show Name:</label>
              <input type="text" class="form-control" name="show_name" value="{{ $show->show_name }}"/>
          </div>
          <div class="form-group">
              <label for="price">Show Genre :</label>
              <input type="text" class="form-control" name="genre" value="{{ $show->genre }}"/>
          </div>
          <div class="form-group">
              <label for="price">Show IMDB Rating :</label>
              <input type="text" class="form-control" name="imdb_rating" value="{{ number_format($show->imdb_rating, 2) }}"/>
          </div>
          <div class="form-group">
              <label for="quantity">Show Lead Actor :</label>
              <input type="text" class="form-control" name="lead_actor" value="{{ $show->lead_actor }}"/>
          </div>
          <button type="submit" class="btn btn-primary">Update Show</button>
      </form>
  </div>
</div>
@endsection

In this file, you can show the values of the particular row using its unique id inside the form fields.

So, when you hit this URL: http://localhost:8000/shows/1/edit or http://laravel6.test/shows/1/edit, you will see row edit form.

Create Edit and Update Operation

Add following code inside ShowController update() function.

// ShowController.php

public function update(Request $request, $id)
{
        $validatedData = $request->validate([
            'show_name' => 'required|max:255',
            'genre' => 'required|max:255',
            'imdb_rating' => 'required|numeric',
            'lead_actor' => 'required|max:255',
        ]);
        Show::whereId($id)->update($validatedData);

        return redirect('/shows')->with('success', 'Show is successfully updated');
}

So now, you can edit and update all the data into the database successfully.

Step 9. D – create delete row functionality

Write following code inside ShowController destroy function to to remove show row :

// ShowController.php
public function destroy($id)
{
        $show = Show::findOrFail($id);
        $show->delete();

        return redirect('/shows')->with('success', 'Show is successfully deleted');
}

We have completed a Laravel 6 CRUD operations tutorial with the example from scratch.

If you are interested in FrontEnd framework like Vue.js with Laravel or Angular with Laravel (Code is on Github as for this tutorial) :

  1. Vue Laravel CRUD example https://appdividend.com/2018/11/17/vue-laravel-crud-example-tutorial-from-scratch/
  2. Angular Laravel Tutorial Example https://appdividend.com/2017/09/22/laravel-5-5-angular-4-tutorial-example-scratch/

https://appdividend.com/2019/09/13/how-to-import-and-export-data-in-csv-excel-in-laravel-6/
https://appdividend.com/2019/09/13/laravel-6-generate-pdf-from-view-example-tutorial-from-scratch/
https://appdividend.com/2019/09/04/how-to-upgrade-laravel-valet-and-update-to-laravel-6/
https://appdividend.com/2019/04/08/laravel-collections-search-method-tutorial-with-example/
https://appdividend.com/2019/04/03/laravel-collections-filter-method-tutorial-with-example/
https://appdividend.com/2018/08/15/laravel-file-upload-example/
https://appdividend.com/2018/02/09/laravel-multiple-files-upload-tutorial-example/
https://appdividend.com/2018/02/08/laravel-ajax-validation-tutorial-scratch/
https://appdividend.com/2018/02/07/laravel-ajax-tutorial-example/


Laravel 6 continues the improvements made in Laravel 5.8 by introducing the following features.

  1. Semantic versioning – serverless deployment platform for Laravel, powered by AWS
  2. Compatibility with Laravel Vapor
  3. Improved authorization responses
  4. Job middleware
  5. Lazy collections
  6. Sub-query improvements
  7. The extraction of frontend scaffolding to the laravel/ui Composer package

https://appdividend.com/2018/10/31/how-to-use-php-in-visual-studio-code/ – For PHP Developers.

See https://github.com/slavkoss/fwphp/ (J:\awww\www\readme.md).

B12phpfw does not use jQuery and AJAX, see examples in https://github.com/slavkoss/fwphp/tree/master/fwphp/glomodul/z_examples/AJAX

12. PHP menu & CRUD code skeleton (B12phpfw) comparison

Featured

Revised November 2021 October 2020, December 2019. Original post was published in February 2019.
Download https://github.com/slavkoss/fwphp/ . My articles before this are not needed to learn B12phpfw.

November 2021 version 8.0.0 (requires PHP ver. >= 7). Download  contained many learning examples, but no more because three modules – packages :  Mnu (menu code skeleton), Msg (Blog – compound module) and Mkd  contain enough (not to simple)  PHP code for learning, create large sites CRUD pages and own WYSIWYG web editor. To simple learning code (frequent in learning sources books and internet) is dangerous, leads to wrong coding, which is one of reasons why I have 8 versions. Version 8 is in my opinion smallest code to learn serious web programing.

What’s new in version 8 :

  1. Autoload.php is refactored, much simpler, see old z_NOT_USED_TO_COMPLICATED_Autoload_1stVersion.php
    This is good case showing that first code versions are to complicated code – very frequent case – which is one of reasons why I have 8 versions.
  2. Shares are not any more in \zinc folder but in in vendor folder eg \vendor\b12phpfw\Autoload.php (below web server doc root eg J:\awww\www\). Site roots are on same place in folders hierarchy eg \fwphp (may be named site_x). Also group of modules eg \fwphp\glomodul. Also modules eg \fwphp\glomodul\blog – dir like oracle Forms form module.
  3. PHP 8 (ver. 7 still works) and Bootsrap 5
<?php
http://dev1:8083/fwphp/www/
// J:\awww\www\fwphp\www\index.php
namespace B12phpfw\site_home\www ;

use B12phpfw\core\b12phpfw\Autoload ;

//1. settings - properties - assign global variables to use them in any code part
$module_path = str_replace('\\','/', __DIR__) .'/' ;
$site_path = dirname($module_path) .'/' ; //to app dir eg "glomodul" dir and app
//to web server doc root or our doc root by ISP $module_towsroot = eg '../../../'
$wsroot_path = dirname(dirname($module_path)) .'/' ;
//or $wsroot_path = str_replace('\\','/', realpath('../../')) .'/' ;
$shares_path = $wsroot_path.'vendor/b12phpfw/' ; //includes, globals, commons, reusables

$pp1 = (object)
[ 'dbg'=>'1', 'stack_trace'=>[str_replace('\\','/', __FILE__ ).', lin='.__LINE__]
, 'module_version'=>'8.0.0.0 Mnu' //, 'vendor_namesp_prefix'=>'B12phpfw'
// $_SESSION["TrackingURL"]=$_SERVER["PHP_SELF"];
// 1p. (Upper) Dirs of clsScriptsToAutoload. With 2p(ath). makes clsScriptToAutoloadPath
// 2p. Dir name of clsScriptToAutoload is last in namespace and use (not full path !).
, 'wsroot_path' => $wsroot_path // to awww/www (or any names)
, 'shares_path' => $shares_path // to b12phpfw, b12phpfw is required dir name
, 'site_path' => $site_path // to fwphp (or any names)
, 'module_path' => $module_path // to fwphp/www (or any names)
//
, 'glomodul_path' => $site_path .'glomodul/'
, 'examples_path' => $site_path .'glomodul/z_examples/'
] ;

//2. global cls loads classes scripts automatically
require($pp1->shares_path . 'Autoload.php');
new Autoload($pp1);

//3. process request from ibrowser & send response to ibrowser :
//Home_ ctr "inherits" index.php ee inherits $p p 1
$module = new Home_ctr($pp1) ; //also instatiates higher cls : Config_ allsites

exit(0);
<?php
// J:\awww\www\vendor\b12phpfw\Autoload.php
namespace B12phpfw\core\b12phpfw ; //Dir name is last in namespace and use 
//use B12phpfw\dbadapter\post\Tbl_crud ; // as Tbl_crud_post ;

class Autoload
{
protected $pp1 ; //M O D U L E PROPERTIES PALLETE like in Oracle Forms

public function __construct(object &$pp1) {
$pp1->stack_trace[]=str_replace('\\','/', __FILE__ ).', lin='.__LINE__ .' ('. __METHOD__ .')';
$this->pp1 = $pp1 ;
spl_autoload_register(array($this, 'autoloader'));
return null ;
}

function autoloader(string $nscls) 
{
//$nscls is namespaced called cls name eg B12phpfw\module\book\Home_ctr
$DS = DIRECTORY_SEPARATOR ;
$nscls_linfmt = str_replace('\\',$DS, $nscls) ; //ON LINUX
$clsname = basename($nscls_linfmt) ; //eg Home_ctr, Config_ allsites, Db_allsites
$module_dir = basename(dirname($nscls_linfmt)) ; //eg Home_ctr, Config_ allsites, Db_allsites
//echo '<pre>$nscls='; print($nscls) ; echo ' $module_dir='; print($module_dir) ; echo '</pre>';

switch ($module_dir) {
case 'b12phpfw': 
$clsscript_path=dirname($this->pp1->shares_path).'/'.$module_dir.'/'.$clsname .'.php' ; 
break;
default:
$clsscript_path=dirname($this->pp1->module_path).'/'.$module_dir.'/'.$clsname .'.php' ; break;
break; 
}
//echo '<p>$clsscript_path='; print($clsscript_path) ; echo ' SAYS: '. __METHOD__ .'</p>';

require $clsscript_path;


}
}

2020.09.30 DONE version 7.0.0 (declare(strict_types=1);).

DBI is improved with trait Db_allsites instead class Db_allsites. Each DB (persistent storage) adapter-class named Tbl_crud :

  1. use B12phpfw\core\zinc\Db_allsites
  2. implements Interf_Tbl_crud

This means that :

  1. eg blog module in blog folder, works much easier with more model classes ee Tbl_crud -s, ee with own Tbl_crud and with other tables Tbl_crud.
  2. eg sole module controller class Home_ctr extends class Config_allsites, no more extends also two DB CRUD classes which is unnatural (but seems easy because logically : all is in Home_ctr).

B12phpfw core (CRUD) code – How to get ONLY banana ?

It is not easy to see need to why convert code from procedural MVC to OOP MVC with namespaces and autoloading. For navigation (url-s, links) code procedural and OOP is same – OOP does not help. Procedural MVC user module code is more clear and readable. So why is OOP better ?

Some say: “is OOP mistake ?” – eg lack of reusability in OOP – to get banana (some method or attribute) you get also gorilla holding banana and whole gorilla`s jungle (all higher classes with complicated dependencies). It is why B12phpfw code skeleton is for CRUD modules (is not required for Mnu and Mkd modules but I put both on B12phpfw code skeleton).

Interfaces help to get ONLY banana, but coding is complicated – I could find only strong-talk-weak-work code examples about advanced use of interfaces.

  1. My not complicated interface Interf_Tbl_crud I made to standardize coding Tbl_crud model adapter classes and Db_allsites shared model class. Each simple (ee one table) module like “invoice items” module has own dir and own Tbl_crud class leading to more than 100 Tbl_crud.php model adapter classes scripts in big application (eg material and financial book keeping).
    J:\awww\www\vendor\b12phpfw\Interf_Tbl_crud.php (... hits)
    Line 20: static public function get_cursor( //instead rr
    Line 28: static public function cc(object $pp1, array $other=[]): object ; //create row
    Line 31: static public function rrnext(object $cursor ): object ; //read next from $c=get_cursor
    Line 34: static public function rrcnt( //string $sellst, //read count rows in table
    ...
  2. With DBI trait Db_allsites I eliminated two higher DB classes. So if banana (some method or attribute) is get_cursor (read) from more tables it is not in two higher DB classes which seems simplest solution but caused complicated coding in version 6. Eg invoice module works with two (or three – bill) tables : invoice and invoice_items.get_cursor banana is not in jungle (two higher DB classes) any more, gorilla and jungle is only one abstract class Config_allsites which is de facto assigning $pp1 = properties (Oracle Forms form property palete made global).
    1. Banana $pp1 = properties palette may cause difficulties in aggregate (compound, composed, multiplex) modules like Blog, Invoice… but $pp1 is inevitably (imminence, necessity) gorilla-jungle and can not be further simplified. I worked 20 years with $pp1 and globals jungle (Oracle Forms 6i) which i not so well accomplished as in B12phpfw .

    See https://phpthewrongway.com/, or Joe Armstrong why OOP sucks http://harmful.cat-v.org/software/OO_programming/why_oo_sucks.

    Similar “simplest solution” three dirs M,V,C is (I think) bad, I have opinion -:) for 3dirs lovers who put in foreground coding technic (M,V,C code separation) instead pages (functionality, business logic , eg invoice page).

During winter 2019/2020 year (much to late because I tested lot what others did) I made Version 6. of menu and CRUD PHP code skeleton (own framework named “B12phpfw”) – core code is about 50 kB.
I also made posts module “Msg” with posts edited with WYSIWYG Markdown SimpleMDE editor (or HTML WYSIWYG Sumernote editor or … any editor you wish). Msg module is based on B12phpfw, also very small code.

B12phpfw code skeleton and Msg application on B12phpfw skeleton is minimal PHP code to learn (medium/advanced knowlege) PHP !

Why ?

  1. I do not like proposed solutions in best php frameworks (Laravel, Simfony, Yii…) and learning sources (internet, books).
  2. I think that eg module invoice php code should be in own folder like Oracle Forms form invoice.fmb instead all forms/reports in 3 folders: M, V, C).
  3. I think that should be simple/fast/professional : shares (globals), routing, dispaching, classes loading , web rich text editing – it is why I spend many hours coding my B12phpfw (huge time wasting which should do software authors, not sw users-programers like me).

Compared B12phpfw Msg (blog) module and TraversyMVC blog module and Mini3 module URLs Youtube songs adresses

Why I do not like proposed solutions in existing PHP frameworks and what I did to (I hope) improve fw code. Red colored features and three asterisks *** are main reasons for B12phpfw, but I improved also other features.

TraversyMVC (has video) and Mini3 are simplified, with some (many?) differences Laravel, Simfony, Yii… B12phpfw is much more different – see red colored features.

Feature B12phpfw TraversyMVC and Mini3
1. ***Modules in own folder like Oracle Forms .fmb has – it is main reason for B12phpfw ! has not like Mini3 – all forms/reports in 3 folders: M, V, C
2. Name spaced classes (functional name spacing) has has not – no functional, no positional (paths) name spacing, Mini3 MVC PHP fw which is in my opinion better than TraversyMVC : https://github.com/panique/mini3 has name spaced classes
3. Number of folders (my opinion) optimal to many like Mini3
4. Minimal PHP code to learn (medium) PHP (my opinion) optimal (but we could add additional code) good but not enough like Mini3 eg see WYSIWYG, globals…
5. Functional methods, attr. etc naming (my opinion) good could be better
6. ***Global classes, methods etc (my opinion) good bad like Mini3
7. (Posts edited with any) WYSIWYG editor has has not like Mini3
8. ***Home_ctr or Home_mdl CRUD layer methods do not know for underlaying Db_allsites layer PDO methods, MySql, Oracle… has much improved has not like Mini3
9. OOP has has like Mini3
10. namespaces (own PSR-4 (or Composer’s) autoloading classes scripts) improved has not, Mini3 has
11. ***All scripts are included (ee no http jumps except some jumps to other module) has has not, Mini3 has, B12phpfw took it from Mini3
12. jQuery only for Bootstrap 5 yes yes, Mini3 has own CSS
13. no AJAX, no JSON yes yes, Mini3 has basic jQuery AJAX explained
14. server side validation has has like Mini3
15. authentification (log in / out) has has, Mini3 has not
16. authorization (only logged in users may execute some code ee CRUD code…) has has, Mini3 has not
17. ***Own debugging very simple and useful : msg in pre tag or popup JS msg). xdebug also helps. has has not like Mini3

11. PHP CMS – XAMP 64 bit on Windows 10, flat files CRud (u, d in Op.Sys – WYSIWYG SimleMDE or Summernote) or relational DB tblrows CRUD

Revised 2020.03.26 Code download : https://github.com/slavkoss/fwphp
I made B12phpfw ver. 6 code skeleton on which are modules Mnu, Blog (Msg), Mkd and many PHP learning examples.

Conclusion for this and my previous 10 posts

Posts are organized as PHP learning book, so I change previous posts periodically !

5W of every activity (highest ideas, categories, eg in journalism…)

who: Web site – menu & CRUD code skeleton applied to 3 modules (wrong to say applications) : “Mnu”, “Blog (Messages, Msg)”, “Mkd” in dirs :

  1. WEBSERVERDOCROOT\fwphp\www (fwphp is group of applications, www is menu appl consisting of one module)
  2. WEBSERVERDOCROOT\fwphp\glomodul\blog (glomodul is “application global modules” = group of global modules, )
  3. WEBSERVERDOCROOT\fwphp\glomodul\mkd

where(is code) : All Sites level Globals, Modules Globals, Menu code skeleton, Config classes, Crud classes.

when: Clear visible programming stepssignal flow, data flow & code flow

what: Basic Menu & CRUD code skeleton for (who)

how:

  1. FUNCTIONAL (DECLARATIVE) NAMING – descriptions of WHAT, NOT HOW STEPS -eg not programming steps M, V, C. Directory named invoice_fmb, means bussiness proces, not how steps (ee not 3 dirs M, V, C for all modules – fmb-s) !
  2. index.php is MAIN MODULE’S SINGLE ENTRY POINT ee all (submenus) calls go through this script. Here is configuration minimized, CONVENTIONS maximized. Same all other modules.
  3. simple OWN DEBUGGING and XDEBUG.
  4. CLASSES FOR: Config, (Controllers), Models (CRUD), not for Views but could be.
  5. namespaces & own autoloading class scripts. Composer’s PSR-4 is problem for not 3 dirs M, V, C for all modules but each module in own dir (huge difference) ?
  6. pagination in Blog pages
  7. beautiful urls without web server url rewritting (see QS=”?” constant.
  8. search/filtering/sort in Blog pages
  9. password_verify and password_hash functions explained (in z_examples)
  10. RTE (Rich Text Edit) markdown (SimpleMDE & Parsedown MD2HTML) or HTML (Summernote)

why: Not found hows above in learning sources : Simplest possible code skeleton, newest PHP coding style, good code explanations – code help.

Main (Root) module contains main index.php

www subdir in fwphp dir contains root module, site’s index.php. Has links on many test-learn examples.

Mkd module is Dreamweaver replacement

Can WYSIWYG edit:

  1. markdown using SimpleMDE or other
  2. or html using Summernote or other.

No relational database CRUD (so code is simpler) but similar, based on same B12phpfw fw (program skeleton) as Msg realational DB tables rows PDO CRUD module, so Mkd is good for learning MVC framework skeleton coding. I think B12phpfw is best-simplest DB PDO CRUD framework (for framework haters which also am I partially: it is not framework, it is standardized basic code skeleton) . Why version 6 ? B12phpfw is good example how small but important changes in fw code cause:

  1. lot of work
  2. and when done much simpler use of basic code skeleton.

 

PREREQUISITES FOR PHP WEB DEVELOPMENT

1. XAMPP 64 bit, php 7.4.2 https://www.apachefriends.org/download.html (I do not use WAMP SERVER anymore)

If no XAMPP (more work) : PHP (for Windows thread safe) : php 7.4.x needs VC15 or VS16 (Visual Studio 2017 or 2019 compiler respectively) Apache : https://www.apachelounge.com/download/

2. CONFIG SCRIPTS see 00info_php2.php – all config scripts are here

J:\xampp\apache\conf\httpd.conf J:\xampp\apache\conf\extra\httpd-vhosts.conf C:\Windows\System32\drivers\etc\hosts J:\xampp\php\php.ini

3. CONNECT PHP 7.2.4 TO OracleXE 11.2

ORACLE 11g PDO & OCI8 EXTENSION – OPTIONAL

php_pdo_oci.dll comes with XAMPP.

In php.ini extension=pdo_oci and extension=php_oci8_11g.dll (.dll is optional, not required)

oci8.default_prefetch = 100

https://pecl.php.net/package/oci8 (for XAMPP on Windows thread safe) ver. 2.2.0

2018-12-10 copy 1_php_oci8-2.2.0-7.4-ts-vc15-x64.zip to J:\xampp\php\ext and unzip php_oci8_11g.dll .

CLI PHP : J:\xampp\php\php.exe (before I used J:\wamp64\bin\php\php7.2.9\php.exe)

ORACLE 11g OCI8 EXTENSION ON NETWORK : OR for PC on on network ? : Feb 6 2018 Christopher Jones : ORACLE CLIENT LIBRARIES of same 32-bit or 64-bit architecture as PHP and are first in PATH. If you use Instant Client you need to have the correct VS Redistributable, see

  1. 64 bit http://www.oracle.com/technetwork/topics/winx64soft-089540.html or
  2. 32 bit http://www.oracle.com/technetwork/topics/winsoft-085727.html

4. COMPOSER DEPENDENCY MANAGER FOR PHP (CODE DOWNLOADER)

For XAMPP on WINDOWS just install https://getcomposer.org/Composer-Setup.exe from page https://getcomposer.org/download/ .

WAMP does not like php in PATH variable. So composer update does not work. [*master] J:\awww\w\fwphp> J:\wamp64\bin\php\php7.2.9\php.exe C:\composer\composer.phar update (1) or better C:\composer\composer7.bat : Save the file along with the originally installed composer.bat @echo OFF :: in case DelayedExpansion is on and a path contains ! setlocal DISABLEDELAYEDEXPANSION J:\wamp64\bin\php\php7.2.9\php.exe “%~dp0composer.phar” %* Now call php7 composer with the new command: [*master] J:\awww\w\fwphp> composer7 selfupdate (1.7.2, Use composer self-update –rollback to return to version 1.7.1) composer7 update (2) is same as (1)

5. GIT MULTIUSER SCRIPTS SYNCHRONIZER see Git book

see https://github.com/slavkoss/fwphp#swfw

 

WAMP 64 bit 2018-05-25 on Windows 10 64 bit – I do not use WAMP or ZWAMP anymore

Seems simpler than ZWAMP – no entries in PATH variable. Composer works after reinstal (asks php.exe dir) – see below.

Composer manual Command-line installation – I do not use this

For XAMPP on WINDOWS just install https://getcomposer.org/Composer-Setup.exe from page https://getcomposer.org/download/ .

To automate the installation on Linux only, use the guide on installing Composer programmatically.

  1. Deinstall Composer if installed
  2. cd J:\wamp64\www\fwphp J:\wamp64\bin\php\php5.6.35\php.exe -v PHP 5.6.35 (cli) (built: Mar 29 2018 14:27:15) Copyright (c) 1997-2016 The PHP Group Zend Engine v2.6.0, Copyright (c) 1998-2016 Zend Technologies
  3. J:\wamp64\bin\php\php5.6.35\php.exe -r “copy(‘https://getcomposer.org/installer‘, ‘composer-setup.php’);”J:\wamp64\bin\php\php5.6.35\php.exe -r “if (hash_file(‘SHA384’, ‘composer-setup.php’) === ‘544e09ee996cdf60ece3804abc52599c22b1f40f4323403c44d44fdfdd586475ca9813a858088ffbc1f233e9b180f061’) { echo ‘Installer verified’; } else { echo ‘Installer corrupt’; unlink(‘composer-setup.php’); } echo PHP_EOL;” outputs : Installer verifiedJ:\wamp64\bin\php\php5.6.35\php.exe composer-setup.phpoutputs : Composer (version 1.6.5) successfully installed to: J:\wamp64\www\fwphp\composer.phar Use it: php composer.pharJ:\wamp64\bin\php\php5.6.35\php.exe -r “unlink(‘composer-setup.php’);”The 4 lines above will, in order:
    1. Download the installer to the current directory
    2. Verify the installer SHA-384 which you can also cross-check here https://composer.github.io/pubkeys.html
    3. Run the installer – will check some php.ini settings, warn you if they are set incorrectly, and then download the latest composer.phar in the current directory
    4. Remove the installer
  4. Create a new composer.bat file alongside composer.phar: J:\wamp64\www\fwphp>echo @J:\wamp64\bin\php\php5.6.35\php.exe “%~dp0composer.phar” %*>composer.bat
  5. Add directory J:\wamp64\www\fwphp to your PATH environment variable if it isn’t already. For information on changing your PATH variable, please see this article https://www.computerhope.com/issues/ch000549.htm and/or use Google.
  6. Close your current terminal. Test usage with a new terminal: C:\Windows\System32>composer -V Composer version 1.6.5 2018-05-04 11:44:59

1c. Web server at home, DDNS (dynamic DNS), access my dyndns from local network, PHP, CURL, OpenSSL

HOME

DDNS – Dynamic DNS

Access my dyndns from local network ee access my dynamic DNS domain name inside my LAN.

I dont want to redirect from Dyn hostname to 192.168.x.x (create an entry in my hosts file with Dyn hostname and the LAN IP), but how i can access from inside network to my dyndns ?

Solution below would be better without (see below) localtest.me or fuf.me but I do not know how to do it.

I did not used this (not clear explanations):
Few home routers support what’s known as NAT Reflection or Loopback, see http://opensimulator.org/wiki/NAT_Loopback_Routers. NAT loopback connection basically is accessing a LAN side device via it’s NAT’ed WAN IP from the internal LAN network.
Setting up Microsoft Loopback adapter allows you to have multiple service appear at the same port.

WORKS My home site from local network :

http://phporacle.mooo.com.localtest.me:8083/

http://phporacle.mooo.com.fuf.me:8083/

WORKS  My home site from inet is without (see below) localtest.me or fuf.me :

http://phporacle.mooo.com:8083/

 

How I did it :

11111 Open port in router and firewall

On Windows XP PC (different router) subdomains like fuf.me or localtest.me are not needed,
but on Win 8.1 and 10 router Siemens Gigaset SX763 WLAN dsl  are now needed (few monts ago not !!).

1. open port 8083 or simmilar in router – port 8083 forward to my PC static IP 192.168.x.x (ipv4 network adapter properties !)
2. open port 8083 in Windows firewall for TCP access (UDP also ?)
2.1 WINKEY+R -> type WF.msc
2.2 In the Windows Firewall with Advanced Security, in the left pane,
left-click Inbound Rules -> click New Rule in the action pane.
2.3 In the Rule Type dialog box, select Port, and then click Next…

ZWAMP does next in Windows firewall :
httpd.exe      J:\zwamp64\vdrive\.sys\Apache2\bin\httpd.exe
mysqld.exe   J:\zwamp64\vdrive\.sys\mysql\bin\mysqld.exe

My C:\Windows\System32\drivers\etc\hosts
127.0.0.1      localhost dev1
::1                 localhost dev1

22222 What Is My IP? see code at end of this page

The request came from:
fe80::8179:3afd:d500:28f5

My home web server IP : 89.164.194.29

or
http://www.canyouseeme.org/

https://www.whatismyip.com/

http://www.portchecktool.com/

http://www.yougetsignal.com/tools/open-ports/

https://bestvpn.org/whats-my-ip/

https://www.dynu.com/networktools/portcheck

33333 Send my IP to DDNS provider

DDNS client

or

http://YOURDDNSUSRNAME:YOURDDNS[email protected]/nic/update?hostname=phporacle.mooo.com&myip=89.164.194.29

or

rem J:\zwamp64\vdrive\web\utl\wcurl_phporacle.mooo.com.bat
@cls
cd %~DP0
@echo Updating FreeDNS
@J:\CURL\CURL -k http://freedns.afraid.org/dynamic/update.php?RFFqMGxON2s5V1RXSm51VE84bkJjamdIOjE3MDE3ODUw
@pause

or

rem J:\zwamp64\vdrive\web\utl\wget_phporacle.mooo.com.bat
cd %~DP0
J:\CURL\wget -q –read-timeout=0.0 –waitretry=5 –tries=400 –background http://freedns.afraid.org/dynamic/update.php?RFFqMGxON2s5V1RXSm51VE84bkJjamdIOjE3MDE3ODUw

 

 

Public DNS Pointing To localhost (127.0.0.1)

http://www.fidian.com/programming/public-dns-pointing-to-localhost

Hosts File

The first and easiest method is where one edits their hosts file (/etc/hosts in Linux,  C:\Windows\System32\Drivers\etc\hosts for some versions of Windows) and add lines like this:
127.0.0.1 client1.local
127.0.0.1 client2.dev
127.0.0.1 client3
At work, we have up to five different hostnames for each of our clients.  Adding yet another client means dozens of developers that now need to edit their hosts file.  Oh, the pain and agony when you have to do this for hundreds of domains!
What if we could have a single top-level domain that always resolved to localhost?

 

DNS Entries – Windows

If you are using Windows DNS, you can create a new zone (I did not):
dnscmd /RecordAdd local * 3600 A 127.0.0.1
dnscmd /RecordAdd local @ 3600 A 127.0.0.1

dnsmasq – Linux, MacOS

On Linux systems, you can install dnsmasq to pretend to be a real DNS server and actually respond with 127.0.0.1 for all subdomains of a top level domain.  So, if you wanted *.local to always resolve to your own domain, then you can use URLs like this:
http://client1.local/
http://client2.local/
http://client3.local/
You only need to install and set up dnsmasq.  There’s some well-written instructions at http://drhevans.com/blog/posts/106-wildcard-subdomains-of-localhost that you can follow; I won’t repeat them here.
The drawback of this setup is that you now have to install and configure dnsmasq on every machine where you want to use this trick.
What if someone set up DNS entries and basically did this for you?

Available Wildcarded DNS Domains

Some kind hearted people already set up wildcarded domains for you already.  You can use any top level domain below and any subdomain of these and they will always resolve back to 127.0.0.1 (your local machine).

http://localtest.me:8083/   or  http://fuf.me:8083/    – WORKS same as http://localthost:8083/
or same for:    2011 –  September 2017:

  1. http://fuf.me:8083/ – Managed by me; it will always point to localhost for IPv4 and IPv6
  2. http://localtest.me:8083/ – Also has an SSL cert
  3. http://127-0-0-1.org.uk:8083/
  4. http://42foo.com:8083/
  5. http://vcap.me:8083/
  6. http://beweb.com:8083/
  7. http://yoogle.com:8083/
  8. http://lvh.me:8083/
  9. http://ulh.us:8083/
    no more http://ortkut.com:8083/              http://feacebook.com:8083/
    http://ratchetlocal.com:8083/     http://smackaho.st:8083/
Now, with these wildcarded domains, you don’t need to do any modification of your system for requests to come back to your own server.  For instance, you can go to http://127-0-0-1.org.uk:8083/ and the web page request will always head back to your own server.  You’ll still need to configure your web server to answer on this hostname as above said, but at least the DNS portion of the problem is now solved.

 

 

Install  cURL (SSL-enabled) Win command-line tool

 

If you install Git for Windows you get Curl automatically too. There are some advantages:

  • Git takes care of the PATH setup during installation automatically.
  • You get the GNU bash, a really powerful shell, in my opinion much better than the native Windows console.
  • You get many other useful Linux tools like tail, cat, grep, gzip, pdftotext, less, sort, tar, vim and even Perl.

http://www.oracle.com/webfolder/technetwork/tutorials/obe/cloud/13_2/messagingservice/files/installing_curl_command_line_tool_on_windows.html

This tutorial shows you how to access Oracle Messaging Cloud Service via the REST interface by using the cURL command-line tool. cURL is free, open software that runs under various operating systems.

This tutorial demonstrates cURL on a Windows 64-bit operating system that is enabled for the secure sockets layer (SSL). The authentication aspects of the Messaging Cloud Service require an SSL-enabled environment.

Your first task is to install the appropriate version of cURL for your SSL-enabled environment.

There is an ordered series of steps to follow to install cURL on Windows. There are two libraries to install and they must be installed before cURL will work with SSL. Also, they must be installed in this order to work. Do not skip the step to install a recent certificate.

Install Visual C++ 2008 Redistributable Package.

For 64-bit systems: Visual C++ 2008 Redistributables (x64) from http://www.microsoft.com/en-us/download/details.aspx?id=15336

For 32-bit systems: Visual C++ 2008 Redistributables (x32)

Install Visual C++ 2010 Redistributable Package.

For 64-bit systems: Visual C++ 2010 Redistributables (x64) from http://www.microsoft.com/en-us/download/details.aspx?id=14632

For 32-bit systems: Visual C++ 2010 Redistributables (x32)

Install Win(32/64) OpenSSL v1.0.0k Light from http://www.shininglightpro.com/products/Win32OpenSSL.html.

For 64-bit systems: Win64 OpenSSL v1.0.0k Light

For 32-bit systems: Win32 OpenSSL v1.0.0k Light

In your browser, navigate to the cURL welcome page at http://curl.haxx.se and click Download.

On the cURL Releases and Downloads page, click the link for the SSL-enabled version for your computer’s operating system, download the zip file, and install it in a new folder on your computer.

The cURL website offers a wizard to find the appropriate version for your computer’s operating system.

For this tutorial, the 64-bit generic, SSL-enabled version for Windows is selected.
Copy curl.exe file into your Windows PATH folder. By default, this is C:\Windows\System32

Install recent CA Certificates. Do not skip this step.
Download cacert.pem, a recent copy of valid CERT files, from http://curl.haxx.se/docs/caextract.html.
Copy it to the same folder where you placed curl.exe and rename it curl-ca-bundle.crt.
Or: Move this file into your Windows PATH folder.

Invoke curl.exe from a command window (in Windows, click Start > Run and then enter “cmd” in the Run dialog box).

You can enter curl --help to see a list of cURL commands.

http://freedns.afraid.org/dynamic/

DDNS record types

Type: A – Point subdomain.domain.com (phporacle.mooo.com) to a hard coded IP Address. Most direct and straight forward option, also note any change you make in the FreeDNS program is reflected on the internet and made live immediately. The only way you will not see immediate results is if you have cached a query on your computer by looking it up PRIOR to configuring it in the FreeDNS program.

Type: MX – Point subdomain.domain.com to a mail server. These type of records are special for just mail servers, they can co-exist with A records, and their only use is for routing mail to a different location. All mail implementations check for this record first before attempting to route an e-mail message. If a MX record does not exist for a host, an e-mail delivery would be attempted directly to the IP that the hostname resolves to.

Type: AAAA – Point subdomain.domain.com to a IPv6 address. Useful for those who are using IPv6 on their personal networks or those who are using a IPv4 to IPv6 tunnel at home.

Type: CNAME – Point subdomain.domain.com to another hostname. Good for those who are using other dynamic DNS services. You can create a CNAME record to another host and whatever subdomain.domain.com you choose here will go to whatever IP address the CNAMEd host has.

Type: NS – Point subdomain.domain.com to another NAMESERVER. If you choose this option, then whatever subdomain.domain.com address you choose using FreeDNS will have to be configured and setup on the destination ADDRESS (nameserver) that you choose. This option basically means you are delegating a FreeDNS host to another DNS server all together, so when you choose this option you are telling every computer on the internet to ask the ‘address’ where subdomain.domain.com is located at. If the host you point an NS record to is not configured to answer for the subdomain.domain.com that you are using in FreeDNS then the subdomain.domain.com host will not resolve.

Type: TXT – Lets you create TXT records, used for a number of different things, most commonly for DKIM records (for combatting spam) so other receiving mail servers can verify email was sent from you by verifying your publically published crypto-signature. Wrap your TXT “destination” in quotes (don’t worry, the system will remind you if you forget).

Type: SPF – A anti-spam record, good to have on any domain you’re sending email with. See https://www.spfwizard.net/ for more details.

Type: LOC – A means for Expressing Location Information in the Domain Name System.

RFC1876 has the complete explanation.

To find your latitude/longitude location, you may find Map-O-Rama of use.

Type: RP – The Responsible Person RR. RP has the following format:

RP <mbox-dname> <txt-dname>

Both RDATA fields are required in all RP RRs.

The first field, <mbox-dname>, is a domain name that specifies the mailbox for the responsible person.

The second field, <txt-dname>, is a domain name for which TXT RR’s exist. A subsequent query can be performed to retrieve the associated TXT resource records at .

RFC1183 has the complete explanation.

Type: SRV – A ‘service’ record, used by Session Initiation Protocol (SIP), and the Extensible Messaging and Presence Protocol (XMPP). Also used by Minecraft.

Some examples:

Type: SRV
Subdomain: _service._protocol.subdomain
Destination: 4 fields, separated by a space (Priority Weight Port Target)

Some more random examples:

Type: SRV
Subdomain: _minecraft._tcp.mc
Domain: yourdomain.com
Destination: 0 0 25676 dns.yourdomain.com

Type: SRV
Subdomain: _jabber._tcp
Domain: yourdomain.com
Destination: 10 0 5269 jabber.yourdomain.com

Type: SRV
Subdomain: _jabber._tcp
Domain: yourdomain.com
Destination: 20 0 5269 xmpp-server1.l.google.com

Cool tips / hidden features

1). If you use other dynamic DNS services and plan to continue using them, one easy way to keep your IP address up to date, is by simply changing your record to a CNAME in the ‘subdomains’ area to your other dynamic DNS hostname, then you do not need to bother setting up a update script to Free DNS.
2). If you use only Free DNS, and have multiple hostnames to update, you can leave 1 of them a A record, and make the rest of them CNAME’s so you do not have to issue multiple updates each time.
3). If you want to redirect your users to a webpage when you go offline, you can add the string &offline=1 to your update string, and your record will then be converted to a web forward record. To edit the offline URL, click ‘subdomains’, then click the subdomain you wish to edit, then click ‘forward to URL’ and fill it out with all your offline info, then save it.
4). If you are behind a firewall and Free DNS is not detecting your IP address correctly, you can add &address=127.0.0.2 to the update string, to override Free DNS auto-detection. To see the order and/or HTTP variables checked that Free DNS attempts to detect your IP address, you can click here

DEFINITIONS:
Direct URL – The URL used to update FreeDNS with your current IP address. You can right click the link and copy shortcut to get the update URL.

Grab URL Script – This is a link that generates a Windows .bat file you can use to update your IP address. You may however prefer to use Free DNS Clients available for a cleaner more automatic solution, not all of these are free.

Edit Record – Self explanatory. If you don’t know what this means, contact me for a brutal hazing.

The expiration time value is controlled by FreeDNS. In FreeDNS, the cache values (called a TTL, time to live) is set to 3600 seconds by default (1 hour). With that said, you must wait a maximum of one hour for your previous cache to expire.

If you wish to verify that your update has made it into FreeDNS, instead of waiting, you can query against freedns.afraid.org’s nameservers directly from your computer like so:

click start menu -> click run -> type “nslookup” without quotes, press enter. You should see a black box. Inside of it, type:

“server ns1.afraid.org” press enter
Default Server:  ns1.afraid.org
Addresses:  2607:f0d0:1102:d5::2
50.23.197.94

then phporacle.mooo.com.afraid.org.fuf.me:8083  = “yourhostname.afraid.org” press enter
*** ns1.afraid.org can’t find phporacle.mooo.com.afraid.org.fuf.me:8083: No response from server

There are also 3rd party DNS utilities available for windows that would even let you see how many seconds are left in the cache in your ISPs nameserver.

tempr.email = Fake email for email askers on inet :
[email protected] https://tempr.email/inbox.htm

Code

<?php
// J:\awww\apl\dev1\utl\ddns_whatismyip.php
// proxy_intermediate_buffer_server_request_hdr is modified
// returns first forwarded IP match it finds
// forwarded IP is of who started request
function forwarded_ip() {
 $keys = array(
 'HTTP_X_FORWARDED_FOR', 
 'HTTP_X_FORWARDED', 
 'HTTP_FORWARDED_FOR', 
 'HTTP_FORWARDED',
 'HTTP_CLIENT_IP', 
 'HTTP_X_CLUSTER_CLIENT_IP', 
 );
 
 foreach($keys as $key) {
 if(isset($_SERVER[$key])) {
 $ip_array = explode(',', $_SERVER[$key]);
 foreach($ip_array as $ip) {
 $ip = trim($ip);
 if(validate_ip($ip)) {
 return $ip; 
 }
 }
 }
 }
 return '';
}

function validate_ip($ip) {
 if(filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE 
     | FILTER_FLAG_NO_RES_RANGE) === false) {
 return false;
 } else {
 return true;
 }
}

$remote_ip = $_SERVER['REMOTE_ADDR'];
$forwarded_ip = forwarded_ip();
 
?>

<span style="font-weight: bold;"></span><br>
<h2>22222 What Is My IP?</h2>
 
<p>The request came from:<br>
 <strong><?php echo $remote_ip; ?></strong>
 </p>

 <?php if($forwarded_ip != '') { ?>
 
<p>The request was forwarded for:<br>
 <strong><?php echo $forwarded_ip; ?></strong>
 </p>

<?php } 

exec("del wip_web_servera.txt");
exec("J:\CURL\wget.exe -qO - http://www.icanhazip.com > wip_web_servera.txt");
if (file_exists("wip_web_servera.txt")) {
 $wip_web_servera=trim(file_get_contents("wip_web_servera.txt"));
 echo '<h2>'."My home web server IP : $wip_web_servera".'</h2>'; 
 
}
?>

or<br>
<a href="http://www.canyouseeme.org/" target="_blank">http://www.canyouseeme.org/</a><br>
<br>
<a href="https://www.whatismyip.com/" target="_blank">https://www.whatismyip.com/</a><br>
<br>
<a href="http://www.portchecktool.com/" target="_blank">http://www.portchecktool.com/</a><br>
<br>
<a href="http://www.yougetsignal.com/tools/open-ports/" 
      target="_blank">http://www.yougetsignal.com/tools/open-ports/</a>&nbsp;
<br>
<a href="https://bestvpn.org/whats-my-ip/" target="_blank"><br>
https://bestvpn.org/whats-my-ip/</a><br>
<br>
<a href="https://www.dynu.com/networktools/portcheck" target="_blank">
     https://www.dynu.com/networktools/portcheck</a><br><br>
<br>

<h2>33333 Send my IP to DDNS provider</h2>
DDNS client<br>
<br>
or<br>
<br>
<a href="http://YOURDDNSUSRNAME:YOURDDNSPSW@freedns.afraid.org/nic
/update?hostname=phporacle.mooo.com&amp;myip=<?=$wip_web_servera?>" 
target="_blank">http://YOURDDNSUSRNAME:YOURDDNSPSW@freedns.afraid.org/nic
/update?hostname=phporacle.mooo.com&amp;myip=<?=$wip_web_servera?></a>

 

 

1b. Install Apache, PHP, localhost SSL (https) On Windows 10, all newest 64 bit

HOME
Download config and php test files:  0_Apache24_conf_extra_PHP_ini.zip

Everything works. If I forgot something see URL-s in this article wich served me as tutorials. ZWAMP or simmilar and virtual hosts are not used for this basic example – Apache and PHP are extracted in C: .

Output of C:\Apache24\htdocs\index.php
(see 0_Apache24_conf_extra_PHP_ini.zip) :

Glavni izbornik (Home)

 HTML 5, CSS 3, JS, SSL.                                                             Help
1111111111 2222222222 3333333333 4444444444   444444      Home refresh (http)
4444444444 4444444444 4444444444                                        Home https

C:\Apache24\htdocs\index.php says: JS says: location.protocol=https:

 

https://www.proy.info/how-to-enable-localhost-https-on-wamp-server/
Posted On May 19th, 2017

I did mostly see below Masim Man Dec 1, 2016
1. HOW TO SET UP APACHE WITH SSL (HTTPS) ON LOCALHOST
but URL above has some clearer configs

Step 1: Download and unpack Apache lounge 64 bit (Windows 10 64 bit)
and PHP Version 7.1.9 non thread safe
httpd-2.4.27-Win64-VC15.zip, mod_fcgid-2.3.9-win64-VC15.zip
php-7.1.9-nts-Win32-VC14-x64.zip
SEE HOW TO UNPACK zip-s above : https://www.dionysopoulos.me/233-apache-mysql-php-server-on-windows-with-multiple-simultaneous-php-versions.html
or 0_Apache24_conf_extra_PHP_ini.zip above.

we have C:\Apache24 and C:\PHP\7.1.9

Step 2: Download OpenSSL (32 bits/64 bits Windows)
I did not so, see below Masim Man Dec 1, 2016

Step 3: Configure WAMP to use HTTP+SSL=HTTPS
I did not so, see below Masim Man Dec 1, 2016

Step 4: Create SSL Key and Certificate
I did not so, see below Masim Man Dec 1, 2016

Step 5: Copy the Created SSL Key and Certificate file
I did not so, see below Masim Man Dec 1, 2016

Step 6: Open httpd.conf, php.ini & uncomment
Open C:\Apache24\conf\httpd.conf and uncomment:
LoadModule ssl_module modules/mod_ssl.so
Include conf/extra/httpd-ssl.conf
LoadModule socache_shmcb_module modules/mod_socache_shmcb.so
See whole scripts in .zip above.

Step 7: Open httpd-ssl.conf and make the final changes
Open c:\Apache24\conf\extra\httpd-ssl.conf (see .zip above)
find “<VirtualHost _default_:443>” and below that line find and update below configuration according to your setup:
# General setup for the virtual host
DocumentRoot “c:/Apache24/htdocs”
#ServerName www.example.com:443
ServerName localhost:443
ServerAdmin youremail
ErrorLog “c:/Apache24/logs/sslerror.log”
TransferLog “c:/Apache24/logs/sslaccess.log”
SSLEngine on
SSLCertificateFile “c:/Apache24/conf/server.crt”
SSLCertificateKeyFile “c:/Apache24/conf/server.key”
… and so on, see config files in 0_Apache24_conf_extra_PHP_ini.zip.

Open php.ini, uncomment :
extension=php_openssl.dll

Step 8: Test to make sure it works
check if you are getting Syntax is OK
C:\Apache24\bin>httpd -t
https://localhost/index.php

 

https://www.youtube.com/watch?v=Zdl68h_N2lc Masim Man Published on Dec 1, 2016 :

HOW TO SET UP APACHE WITH SSL (HTTPS) ON LOCALHOST

HTTPS (Hyper Text Transfer Protocol Secure) is a protocol for secure communication over a computer network.

Make icon for C:\Windows\SysWOW64\cmd.exe (run as admin). It shows Apache’s openssl:
openssl version -d
OPENSSLDIR: “C:\Program Files\Common Files\SSL”
openssl version
OpenSSL 1.1.0f 25 May 2017

–We create files :
1. C:\Apache24\conf\server.csr              <–OpenSSL certificate request
2. C:\Apache24\conf\server.pem            <–private key

3. C:\Apache24\conf\server.key             <–from .pem
4. C:\Apache24\conf\server.crt              <–from .key, .csr
see  below :
openssl x509 -req -signkey C:\Apache24\conf\server.key -days 1024 ^
-in C:\Apache24\conf\server.csr -out C:\Apache24\conf\server.crt

00000 –INITIAL
Change config path to where you have installed Apache :
cd C:\Apache24\bin
set OPENSSL_CONF=C:\Apache24\conf\openssl.cnf

11111 & 22222 —     ^ = ALTGRKEY+3 (3 two times)
openssl req -config C:\Apache24\conf\openssl.cnf -new ^
   -out C:\Apache24\conf\server.csr -keyout C:\Apache24\conf\server.pem
ANSWERS: only two :
writing new private key to ‘C:\Apache24\conf\server.pem’
Enter PEM pass phrase: test1
Common Name (e.g. server FQDN or YOUR name) []:localhost

33333
openssl rsa -in C:\Apache24\conf\server.pem -out C:\Apache24\conf\server.key
ANSWER: Enter pass phrase for C:\Apache24\conf\server.pem:test1
writing RSA key

44444
openssl x509 -req -signkey C:\Apache24\conf\server.key -days 1024 ^
    -in C:\Apache24\conf\server.csr -out C:\Apache24\conf\server.crt
Outputs:
Signature ok
subject=C = AU, ST = Some-State, O = Internet Widgits Pty Ltd, CN = localhost
Getting Private key

55555
–C:\Apache24\conf\httpd.conf
search ssl, listen, httpd-ssl and uncomment :
LoadModule log_config_module modules/mod_log_config.so
LoadModule setenvif_module modules/mod_setenvif.so
LoadModule socache_shmcb_module modules/mod_socache_shmcb.so
LoadModule ssl_module modules/mod_ssl.so

Listen 80
#live commented <IfModule mod_ssl.c>
Listen 443
#</IfModule>

Include conf/extra/httpd-ssl.conf

C:\Apache24\conf\extra\httpd-ssl.conf
SSLSessionCache “shmcb:c:/Apache24/logs/ssl_scache(512000)”

restart Apache
if will not start:  as sdmin in CLI
C:\Apache24\bin>httpd -t
or :
NOT httpd.exe -k restart but so:
C:\Apache24\bin>httpd.exe  — this shows error message

 

————– NEEDED FOR MS INET BROWSERS :
https://www.youtube.com/watch?v=Hhown6DgC00 Masim Man Published on Dec 2, 2016
HOW TO INSTALL AN APACHE SELF SIGNED CERTIFICATE ON WINDOWS 10
On Windows 10, a Self Signed Certificate that wasnt issued by a recognized certificate authority is not trusted by default. A Self Signed Certificates usually used on Local Web Servers (Localhost) that arent available publicly. In this case you are save to
– bypass the warning on any browsers
– or installing it to a trusted root certification authority in Windows 10.
2click C:\Apache24\conf\server.crt
in Certificate dialog Issued to and Issued by is localhost
click button “Install certificate”
for current user
place in store “Trusted root Cert. Authorities”
remove certificate localhost so:
WINKEY -> mmc -> File -> Add/remove snapp-in -> Certificates
-> Add -> My user account

2a. Oracle 11g PL/SQL Tutorial

Revised December 2021, published May 2017

Main menu – download 27 May 2017 I uploaded  1_pl_sq.zip Oracle 11g PL/SQL Tutorial

Oracle 11g PL/SQL Tutorial about testing developing DB procedures

  1. Three  loops  and three branches
  2. Function, procedure, package, array object
  3. Number, string, date, boolean
  4. DDL
  5. CRUD
  6. Ref Cursor pointer to cursor (ee to record set object variable) – December 2021

1. Three  loops  and three branches

/*
start ...path...02_02Hello_var_loop_if_exception_date.sql

O U T P U T :

~~~~~~~~ Three  L O O P S ~~~~~~~~
--- loop1. LOOP,EXIT WHEN v_cntr>=2 (v_cntr=0,1)
Hello 28.05.2017
Hello 28.05.2017
---
--- loop2. FOR v_cntr IN 1..2 LOOP - IF v_cntr = 2 THEN 
        RAISE_APPLICATION_ERROR(-20001, v_errmsg);
- EXCEPTION - WHEN others THEN - IF sqlcode = -20001...
Hello
Hello , ***v_cntr=2 custom EXCEPTION !!!at!!! IF v_cntr=2 <-- !!
---
--- loop2a. FOR ii IN REVERSE 3..9 LOOP, mod(ii,3) != 0
ii=9
ii=6
ii=3
---
--- loop3. From WHILE v_cntr < 2 LOOP
Hello
Hello
---
---
~~~~~~~~ Three  B R A N C H E S ~~~~~~~~
--- branch1. IF - ELSIF - ELSE - ENDIF
x message
---
--- branch2. searched CASE - WHEN - ELSE - END CASE
aaa
---
--- branch3. simple "CASE x" - WHEN - ELSE - END CASE (as PHP switch - case - default)
I don't know what v_msg is
*/



set linesize 200
set serveroutput oFF
set serveroutput on size 1000000

------------

DECLARE
  v_cntr NUMBER := 0;
  v_system_date CONSTANT DATE := sysdate;
  v_errmsg VARCHAR2(255);
  v_msg VARCHAR2(255) := 'Hello ';
  
  BEGIN
    msg('---');
    msg('~~~~~~~~ Three  L O O P S ~~~~~~~~'); 
    msg('--- loop1. LOOP,EXIT WHEN v_cntr>=2 (v_cntr=0,1)');
  LOOP
    EXIT WHEN v_cntr >= 2; -- 2 loops : v_cntr = 0, 1
    v_cntr := v_cntr + 1;
      
    msg(v_msg || to_char(v_system_date, 'DD.MM.YYYY'));
  END LOOP;


  BEGIN
    msg('---');
    msg('--- loop2. FOR v_cntr IN 1..2 LOOP - IF v_cntr = 2 
          THEN RAISE_APPLICATION_ERROR(-20001, v_errmsg);');
    msg('      - EXCEPTION - WHEN others THEN - IF sqlcode = -20001...');
    
    FOR v_cntr IN 1..2 LOOP
     IF v_cntr = 2 THEN
       v_errmsg:=v_msg || ', ***v_cntr=2 custom EXCEPTION !!!at!!! IF v_cntr=2 <----------- !!!!!!!!';
       RAISE_APPLICATION_ERROR(-20001, v_errmsg);
     END IF;
     msg(v_msg);
    END LOOP;
    
  EXCEPTION
  WHEN no_data_found THEN  msg(
    'no_data_found EXCEPTION --- 2 From FOR v_cntr IN 1..2 LOOP');
  WHEN others THEN
    IF sqlcode = -20001 THEN msg(v_errmsg);
    ELSE RAISE; -- go to end script err handler
    END IF;
  END;
                --O U T P U T S :
                --Hello
                --Hello , ***v_cntr=2 custom EXCEPTION !!!at!!! IF v_cntr=2 
  msg('---');
  msg('--- loop2a. FOR ii IN REVERSE 3..9 LOOP, 
                   mod(ii,3) != 0');
  DECLARE
    v_increment NUMBER := 3;
  BEGIN
    FOR ii IN REVERSE 3..9 LOOP
      IF mod(ii,v_increment) != 0 THEN CONTINUE; END IF;
      msg('ii=' || ii);
    END LOOP;
  END;

      
      
  msg('---');
  msg('--- loop3. From WHILE v_cntr < 2 LOOP');
  v_cntr := 0 ;
  WHILE v_cntr < 2 LOOP
   v_cntr := v_cntr + 1;
   msg(v_msg);
  END LOOP;


  
  
  msg('---'); msg('---');
  msg('~~~~~~~~ Three  B R A N C H E S ~~~~~~~~');
  msg('--- branch1. IF - ELSIF - ELSE - ENDIF');
  v_msg := 'x message';
  IF v_msg LIKE 'x%' THEN msg(v_msg);
  ELSIF v_msg = 'aaa' THEN msg(v_msg);
  ELSE msg('I don''t know what v_msg is');
  END IF;
  
  msg('---');
  msg('--- branch2. searched CASE - WHEN - ELSE - END CASE');
  v_msg := 'aaa';
  CASE 
  WHEN v_msg LIKE 'x%' THEN msg(v_msg);
  WHEN v_msg = 'aaa' THEN msg(v_msg);
  ELSE msg('I don''t know what v_msg is');
  END CASE;
  
  msg('---');
  msg('--- branch3. simple "CASE x" - WHEN - ELSE - END CASE 
                    (as PHP switch - case - default)');
  v_msg := 'x';
  CASE v_msg -- same as PHP switch - case - default
  WHEN 'aaa' THEN msg(v_msg);
  ELSE msg('I don''t know what v_msg is');
  END CASE;
  

END;
/
set serveroutput oFF

go top

2. Function, procedure, package, array object

/*
start ...path...\02_03fn_proc_pck_assoc_arr_object.sql

O U T P U T :

--- 1. fn return_1 SAYS: 1

DML A S S O C I A T I V E  A R R A Y
--- 2. anonymus pl/sql block SAYS: DML associative_array v_array(2)=Hello Again!
--------2.1 robust loop through array
Hello World!
Hello Again!
--------2.2 simple loop through array
Hello World!
Hello Again!

--------2.3 robust loop through array
Doe
King

--------2.4 robust loop through array with delete
Hello World! Date and time: Sunday    on 28 May, 2017 @ 08:12:34

--- 3.1 anonymus pl/sql block SAYS: DDL object_o_person v_person.lname=Doe2

--- 3.2 anonymus pl/sql block SAYS: DDL object_o_person v_person(1).lname=Doe3

--- 4. my_package.crerow_t;  and read it
This is a message

--- 5. print business days
Tuesday 4 of July, 2017
Monday 25 of December, 2017
*/

set linesize 200
set serveroutput OFF
set serveroutput on size 1000000
------------

-- c a l l  f u n c t i o n :
--BEGIN msg('---aaaaa'); END;
BEGIN msg('--- 1. fn return_1 SAYS: '||return_1); END;
/
-- c a l l  p r o c e d u r e :
--BEGIN insert_a_rec(...); END;


-- DML associative_array
DECLARE
  TYPE t_array IS TABLE OF VARCHAR2(30) INDEX BY BINARY_INTEGER;
  v_array t_array;
  v_index BINARY_INTEGER;    
BEGIN
  v_array(1) := 'Hello World!';
  v_array(2) := 'Hello Again!';
  msg('DML A S S O C I A T I V E  A R R A Y');
  msg('--- 2. anonymus pl/sql block SAYS: DML associative_array v_array(2)='||v_array(2));
  
  
  msg('--------2.1 robust loop through array');
  v_index := v_array.FIRST;
  LOOP
    EXIT WHEN v_index IS NULL;
    msg( v_array( v_index ) );
    v_index := v_array.NEXT(v_index);
  END LOOP;
  
  
  msg('--------2.2 simple loop through array');
  FOR ii IN v_array.FIRST..v_array.lAST 
  LOOP
    msg( v_array(ii) );
  END LOOP;
  
END;
/

DECLARE
  TYPE t_varchar2 IS TABLE OF VARCHAR2(100)
    INDEX BY BINARY_INTEGER;
    
  TYPE t_number IS TABLE OF NUMBER
    INDEX BY BINARY_INTEGER;
   
  v_first_name t_varchar2;
  v_last_name  t_varchar2;
  v_salary     t_number;
  
  v_index BINARY_INTEGER;    
BEGIN

  SELECT first_name, last_name, salary 
    BULK COLLECT INTO v_first_name, v_last_name, v_salary
    FROM employees where rownum < 3;
    
    
  msg('--------2.3 robust loop through array');
  v_index := v_last_name.FIRST;
  LOOP
    EXIT WHEN v_index IS NULL;
    msg( v_last_name( v_index ) );
    v_index := v_last_name.NEXT(v_index);
  END LOOP;
  
  
END;
/

DECLARE
  TYPE t_array IS TABLE OF VARCHAR2(30);
  v_array t_array;    
  v_index BINARY_INTEGER;
  v_date DATE := SYSDATE;
BEGIN
  msg('--------2.4 robust loop through array with delete');
  v_array := t_array();
  v_array.extend; v_array(1) := 'Hello World!';
  v_array.extend; v_array(2) := 'Hello Again!';
  
  v_array.DELETE(2);
  v_index := v_array.FIRST;
  LOOP
    EXIT WHEN v_index IS NULL;
    --msg( v_array( v_index ) );
    msg(
      v_array( v_index ) ||
      ' Date and time: ' ||
      to_char(v_date, 'Day') || ' on ' ||
      to_char(v_date, 'FMDD Month, YYYY') ||
      ' @ ' ||
      to_char(v_date, 'HH24:MI:SS')
    );
    v_index := v_array.NEXT(v_index);
  END LOOP;  
END;
/



--------
DECLARE
  v_person o_person;    
BEGIN 
  v_person := o_person('John', 'Doe', 21);
  v_person := o_person('John2', 'Doe2', 22);
  
  msg('--- 3.1 anonymus pl/sql block SAYS: DDL object_o_person v_person.lname='||v_person.lname);
END;
/


DECLARE
  v_person o_person_collec := o_person_collec();    -- table
BEGIN
  v_person.extend;
  --row is TYPE OBJECT :
  v_person(1) := o_person('John3', 'Doe3', 23); 
 
  msg('--- 3.2 anonymus pl/sql block SAYS: DDL object_o_person v_person(1).lname='||v_person(1).lname);
 
END;
/



BEGIN
  msg('--- 4. my_package.crerow_t;  and read it');
  --in sql+ : exec my_package.delrow_t('xx')
  my_package.crerow_t;
  for rx in (select * from t where country_id = 'xx') loop
    msg( rx.country_name );
  end loop;
END;
/


begin
  msg('--- 5. print business days ');
  print_business_days(
     to_date('31-DEC-2016', 'DD-MON-YYYY'),
     to_date('31-DEC-2017', 'DD-MON-YYYY')
  );
end;
/

set serveroutput oFF

go top

3. Number, string, date, boolean

-- ...path...03_01num_string_date_boolean.sql
-- 1. Valid numbers
DECLARE
  vNum NUMBER;
BEGIN
  vNum := 100;
  vNum := 98989898989898;
  vNum := 0.00000000000000001;
  vNum := 10928383.9028282772722626262;
END;
/

-- 2. CHAR versus VARCHAR2
DECLARE
  vc2_Name  VARCHAR2(10) := 'Lewis';
  char_Name CHAR(10)   := 'Lewis';
BEGIN
  IF vc2_Name = char_Name THEN
    dbms_output.put_line('VARCHAR2, CHAR Variables Match');
  ELSE dbms_output.put_line(
     'VARCHAR2, CHAR Variables Do Not Match');
  END IF;  
END;
/


-- 3. String to number conversion
DECLARE
  v_string_var VARCHAR2(10) := '15';
  v_number_var NUMBER;
BEGIN
   v_number_var := TO_NUMBER(v_string_var);
END;

-- 4. Date conversion
DECLARE
  v_string VARCHAR2(30) := '10/30/1998 12:34:03 PM';
  v_date DATE;
BEGIN
  v_date := to_date(v_string, 'MM/DD/YYYY HH:MI:SS AM');
  v_date := to_date(v_string, 'DD.MM.YYYY HH24:MI:SS');
END;
/

-- 5. Timestamp conversion
DECLARE
  v_string VARCHAR2(30) := '10/30/1998 12:34:03.987654 PM';
  v_date timestamp;
BEGIN
  v_date := to_timestamp(v_string, 'MM/DD/YYYY HH:MI:SS.FF AM');
END;


-- 6. Date to char conversion
DECLARE
  v_string VARCHAR2(30) := '10/30/1998 12:34:03 PM';
  v_date DATE;
BEGIN
  v_date := to_date(v_string, 'MM/DD/YYYY HH:MI:SS AM');
  dbms_output.put_line(  to_char(v_date, 'FMDD Month, YYYY') );
END;


-- 7.1 BOOLEAN good example of direct usage
DECLARE
  v_var1 NUMBER := 0;
  v_var2 NUMBER := 1;
BEGIN
  IF v_var1 = v_var2 THEN NULL; END IF;
END;

-- 7.2 BOOLEAN good example for variable reuse
DECLARE
  v_boolean BOOLEAN;
  v_var1 NUMBER := 0;
  v_var2 NUMBER := 1;
BEGIN
  v_boolean := v_var1 = v_var2;
  IF v_boolean THEN NULL; END IF;
END;





-- 7.3 BOOLEAN Poor Example
DECLARE
  v_boolean BOOLEAN;
  v_var1 NUMBER := 0;
  v_var2 NUMBER := 1;
BEGIN
  IF v_var1 = v_var2 THEN v_boolean := TRUE;
  ELSE v_boolean := FALSE;
  END IF;
  
  IF v_boolean THEN NULL; END IF;
END;
/

go top

4. DDL

/*
HR@ora7 27.05.2017 21:21:16> start ...path...\01_02DDL.sql
O U T P U T :
~~~~~ 1. c r e  LOG_ TABLE ~~~~~
~~~~~ 2. c r e  tbl t2 ~~~~~
~~~~~ 3. c r e  tbl emp_names_nds ~~~~~

~~~~~ 1. c r e  p r o c e d u r e  m s g ~~~~~
~~~~~ 2. c r e  p r o c e d u r e  l o g i t ~~~~~
~~~~~ 3. c r e  p r o c PRINT_ BUSINESS_ DAYS ~~~~~
~~~~~ 4. cre fn return_1 ~~~~~
~~~~~ 5. cre R O W TYPE o_ person AS OBJECT ~~~~~
~~~~~ 6. cre T B L TYPE o_ person_ collec AS TABLE OF ~~
~~~~~ 6.1 cre pck my_ package ~~~~~
~~~~~ 6.2 cre pck body my_ package ~~~~~
~~~~~ 7.1 cre pck t2_ dyn_ api ~~~~~
~~~~~ 7.2 cre pck body t2_ dyn_ api ~~~~~
*/
drop TABLE LOG_TABLE;
prompt ~~~~~ 1. c r e  LOG_ TABLE ~~~~~
CREATE TABLE LOG_TABLE
  (
    DATUM DATE,
    MESSAGE VARCHAR2(255 BYTE)
 ) ;
--insert into log_table (date_and_time, message) 
--    VALUES (sysdate, 'Hello World!');
prompt ~~~~~ 2. c r e  tbl t2 ~~~~~
drop TABLE t2 ;
BEGIN
  EXECUTE IMMEDIATE 
  'CREATE TABLE t2 (
       col1 VARCHAR2(25)
     , col2 VARCHAR2(25)
     , col3 VARCHAR2(25)
  )';
END;
/

prompt ~~~~~ 3. c r e  tbl emp_names_nds ~~~~~
drop TABLE emp_names_nds;
CREATE TABLE emp_names_nds (
  last_name VARCHAR2(25), first_name VARCHAR2(20) );
  




prompt ~~~~~ 1. c r e  p r o c e d u r e  m s g ~~~~~
CREATE OR REPLACE PROCEDURE msg(
   p_msg IN VARCHAR2 DEFAULT 'NO MESSAGE')
AS
BEGIN
   dbms_output.put_line(p_msg);
END;
/
--show error



prompt ~~~~~ 2. c r e  p r o c e d u r e  l o g i t ~~~~~
create or replace PROCEDURE logit(
  v_message IN VARCHAR2 DEFAULT 'Hello World!',
  v_output_target IN VARCHAR2 DEFAULT 'T')
AS
  -- v_output target may be T for table or
  --    D for dbms_output
  PRAGMA AUTONOMOUS_TRANSACTION;
  v_date DATE := SYSDATE;

  PROCEDURE do_output(
    v_message IN VARCHAR2,
    v_date IN DATE )
  AS
  BEGIN

    DBMS_OUTPUT.put_line(
        v_message ||
        ' On date ' ||
        to_char(v_date, 'Day') || ' on ' ||
        to_char(v_date, 'FMDD Month, YYYY') ||
        ' @ ' ||
        to_char(v_date, 'HH24:MI:SS')
        ); 
  END;    

  PROCEDURE do_insert(
    v_message IN VARCHAR2,
    v_date IN DATE )
  AS
  BEGIN
    insert into log_table
      (datum, message)
      VALUES (v_date, v_message);
  END;
-------------
BEGIN
  CASE
  WHEN v_output_target = 'T'
  THEN
    do_insert(v_message, v_date);
  WHEN v_output_target = 'D'
  THEN
    do_output(v_message, v_date);
  WHEN v_output_target = 'TD'
    OR v_output_target = 'DT'
  THEN
    do_insert(v_message, v_date);
    do_output(v_message, v_date);
  ELSE

    logit('ERROR v_output_target: ' ||
          v_output_target ||
          ' not found.', 'T' );

  END CASE;

  COMMIT;

END logit;
/



prompt ~~~~~ 3. c r e  p r o c PRINT_ BUSINESS_ DAYS ~~~~~
create or replace PROCEDURE PRINT_BUSINESS_DAYS
  (
      P_START_DATE IN DATE 
    , P_END_DATE IN DATE 
  )
AS
  TYPE t_holidays IS TABLE OF VARCHAR2(100)
    INDEX BY VARCHAR2(30);
  v_dates t_holidays;
  v_loop_increment NUMBER := 0;
BEGIN
  v_dates('01-JAN') := 'Mew Years';
  v_dates('04-JUL') := 'Independence Day';
  v_dates('25-DEC') := 'Christmas Day';

  LOOP
    EXIT WHEN p_start_date + v_loop_increment > p_end_date;

    /*
    IF to_number(to_char(p_start_date 
          + v_loop_increment, 'd'))
      IN (2,3,4,5,6)
    THEN 
      dbms_output.put_line(to_char(p_start_date 
        + v_loop_increment, 'FMDay DD "of" Month, YYYY'));
    END IF;
    */    
    
    -- or :
    IF v_dates.EXISTS(
      to_char(p_start_date + v_loop_increment, 'DD-MON'))
    THEN
    
      IF to_number(to_char(p_start_date 
          + v_loop_increment, 'd'))
        IN (2,3,4,5,6)
      THEN 
        dbms_output.put_line(to_char(p_start_date 
          + v_loop_increment, 'FMDay DD "of" Month, YYYY')); 
      END IF;

    END IF;

    v_loop_increment := v_loop_increment + 1;

  END LOOP;

END PRINT_BUSINESS_DAYS;
/









prompt ~~~~~ 4. cre fn return_1 ~~~~~
CREATE OR REPLACE FUNCTION return_1
RETURN NUMBER
AS
BEGIN
  RETURN 1;
END;
/
--show error

prompt ~~~~~ 5. cre R O W TYPE o_ person AS OBJECT ~~~~~
drop TYPE o_person_collec ;
CREATE OR REPLACE TYPE o_person AS OBJECT (
    fname VARCHAR2(30),
    lname VARCHAR2(30),
    age NUMBER 
);
/
--show error


prompt ~~~~~ 6. cre T B L TYPE o_ person_ collec AS TABLE OF ~~
CREATE OR REPLACE TYPE o_person_collec --table 
  AS TABLE OF o_person; --row is TYPE OBJECT 
/
--show error



prompt ~~~~~ 6.1 cre pck my_ package ~~~~~
CREATE OR REPLACE PACKAGE my_package
AS
  FUNCTION return_1 RETURN NUMBER;
  PROCEDURE crerow_t;
  PROCEDURE delrow_t(p_id in varchar2);
END;
/
prompt ~~~~~ 6.2 cre pck body my_ package ~~~~~
CREATE OR REPLACE PACKAGE BODY my_package
AS
  FUNCTION return_1 RETURN NUMBER AS
  BEGIN
    RETURN 1;
  END;

  PROCEDURE crerow_t AS
  BEGIN
    INSERT INTO t (country_id, country_name)
      VALUES ('xx', 'This is a message');
  END;
  
  PROCEDURE delrow_t(p_id in varchar2) AS
  BEGIN
    delete t where country_id = p_id; --'xx'
  END;

END;  
/



prompt ~~~~~ 7.1 cre pck t2_ dyn_ api ~~~~~
create or replace PACKAGE t2_dyn_api IS
 PROCEDURE insert_row(
    p_col1 IN t2.col1%TYPE,
    p_col2 IN t2.col2%TYPE,
    p_col3 IN t2.col3%TYPE
  );
  
 PROCEDURE update_row(
    p_col1 IN t2.col1%TYPE,
    p_col2 IN t2.col2%TYPE,
    p_col3 IN t2.col3%TYPE
  );
  
 PROCEDURE delete_row(
    p_col1 IN t2.col1%TYPE,
    p_col2 IN t2.col2%TYPE,
    p_col3 IN t2.col3%TYPE
  );  
END;
/

prompt ~~~~~ 7.2 cre pck body t2_ dyn_ api ~~~~~
create or replace PACKAGE BODY t2_dyn_api IS
  PROCEDURE insert_row(
    p_col1 IN t2.col1%TYPE,
    p_col2 IN t2.col2%TYPE,
    p_col3 IN t2.col3%TYPE
  ) 
  AS 

    v_dml_string CLOB;
  
    -- DBMS_SQL variables
    v_cursor_id NUMBER;
    v_rows_fetched NUMBER;
  
  BEGIN

    v_cursor_id := DBMS_SQL.open_cursor;
    
    v_dml_string := 'INSERT INTO t2 (col1, col2, col3) ';
    v_dml_string := v_dml_string || 'VALUES (:col1
         , :col2, :col3) ';
  
    -- Display the string
    logit( v_dml_string, 'D');
 
    DBMS_SQL.PARSE(v_cursor_id, v_dml_string
       , DBMS_SQL.NATIVE);

    DBMS_SQL.bind_variable( v_cursor_id, 'col1', p_col1);
    DBMS_SQL.bind_variable( v_cursor_id, 'col2', p_col2);
    DBMS_SQL.bind_variable( v_cursor_id, 'col3', p_col3);
  
    v_rows_fetched := DBMS_SQL.EXECUTE(v_cursor_id);
    DBMS_SQL.CLOSE_CURSOR(v_cursor_id);
    
    COMMIT;

    logit( 'Rows Fetched: ' || to_char(v_rows_fetched), 'D');

  END;
  
   
  PROCEDURE update_row(
    p_col1 IN t2.col1%TYPE,
    p_col2 IN t2.col2%TYPE,
    p_col3 IN t2.col3%TYPE
  ) 
  AS 

    v_dml_string CLOB;
  
    -- DBMS_SQL variables
    v_cursor_id NUMBER;
    v_rows_fetched NUMBER;
  
  BEGIN

    v_cursor_id := DBMS_SQL.open_cursor;
    
    v_dml_string := 'UPDATE t2 ';
    v_dml_string := v_dml_string || 
               'SET col1 = :col1, 
                    col2 = :col2,
                    col3 = :col3 ';
  
    -- Display the string
    logit( v_dml_string, 'D');
 
    DBMS_SQL.PARSE(v_cursor_id, v_dml_string
       , DBMS_SQL.NATIVE);

    DBMS_SQL.bind_variable( v_cursor_id, 'col1', p_col1);
    DBMS_SQL.bind_variable( v_cursor_id, 'col2', p_col2);
    DBMS_SQL.bind_variable( v_cursor_id, 'col3', p_col3);
  
    v_rows_fetched := DBMS_SQL.EXECUTE(v_cursor_id);
    DBMS_SQL.CLOSE_CURSOR(v_cursor_id);
    
    COMMIT;

    logit( 'Rows Fetched: ' || to_char(v_rows_fetched), 'D');

  END;  
  PROCEDURE delete_row(
    p_col1 IN t2.col1%TYPE,
    p_col2 IN t2.col2%TYPE,
    p_col3 IN t2.col3%TYPE
  ) 
  AS 

    v_dml_string CLOB;
  
    -- DBMS_SQL variables
    v_cursor_id NUMBER;
    v_rows_fetched NUMBER;
  
  BEGIN

    v_cursor_id := DBMS_SQL.open_cursor;
    
    v_dml_string := 'DELETE FROM t2 ';
    v_dml_string := v_dml_string || 
               'WHERE col1 = :col1 AND 
                      col2 = :col2 AND
                      col3 = :col3 ';
  
    -- Display the string
    logit( v_dml_string, 'D');
 
    DBMS_SQL.PARSE(v_cursor_id, v_dml_string
       , DBMS_SQL.NATIVE);

    DBMS_SQL.bind_variable( v_cursor_id, 'col1', p_col1);
    DBMS_SQL.bind_variable( v_cursor_id, 'col2', p_col2);
    DBMS_SQL.bind_variable( v_cursor_id, 'col3', p_col3);
  
    v_rows_fetched := DBMS_SQL.EXECUTE(v_cursor_id);
    DBMS_SQL.CLOSE_CURSOR(v_cursor_id);
    
    COMMIT;

    logit( 'Rows Fetched: ' || to_char(v_rows_fetched), 'D');

  END; 

END t2_dyn_api;
/


/*
-- ORA-01031: insufficient privileges
CREATE OR REPLACE PROCEDURE CREATE_TABLE 
(
  P_TABLE_NAME IN VARCHAR2  
, P_COLUMNS IN DBMS_SQL.varchar2a  
) AS 
  v_ddl_string CLOB;
  v_index PLS_INTEGER;
  -- DBMS_SQL variables
  v_cursor_id NUMBER;
  v_rows_fetched NUMBER;
BEGIN
  IF p_table_name IS NULL OR p_columns.COUNT = 0
  THEN RETURN; END IF;
  
  v_ddl_string := 'CREATE TABLE ';
  v_ddl_string := v_ddl_string || p_table_name || '( '; 
  v_index := p_columns.FIRST;
  
  LOOP
    EXIT WHEN v_index IS NULL;
    IF v_index != p_columns.FIRST
    THEN
      v_ddl_string := v_ddl_string || ', ';
    END IF;
    
    v_ddl_string := v_ddl_string || p_columns(v_index);
    v_index := P_columns.NEXT(v_index);
  END LOOP;
  
  v_ddl_string := v_ddl_string || ')';
  -- Display the string
  logit( v_ddl_string, 'D');
  
  -- Create the table
  v_cursor_id := DBMS_SQL.open_cursor;
  DBMS_SQL.PARSE(v_cursor_id, v_ddl_string, DBMS_SQL.NATIVE);
  v_rows_fetched := DBMS_SQL.EXECUTE(v_cursor_id);
  DBMS_SQL.CLOSE_CURSOR(v_cursor_id);

END CREATE_TABLE;
/

DECLARE
  v_table_name VARCHAR2(30) := 't3';
  v_columns DBMS_SQL.varchar2a;
BEGIN
  v_columns(1)  := 'COL1 VARCHAR2(10)';
  v_columns(5)  := 'COL2 VARCHAR2(2)';
  v_columns(10) := 'COL3 NUMBER';
  -- ORA-01031: insufficient privileges
  CREATE_TABLE(v_table_name, v_columns); 
END;
/
*/

go top

5. CRUD

/*
start ...path...\02_01CRUd_rowtype.sql

O U T P U T :
--- 1. CRUD R employee_id= 115
r_person.salary=3246,86
--- 2. CRUD U employee_id =115
r_person.salary*,95=3084,52
r_person.LAST_NAME=Khoo
--- 3. CRUD D (if exists) employee_id=999
--- 4. CRUD C employee_id=999
r_person.salary=3084,52
r_person.LAST_NAME=Doe
*/
set linesize 200
set serveroutput oFF
set serveroutput on size 1000000
------------
/*
-- rowtype cursor
DECLARE
  CURSOR c1 IS
    SELECT first_name, last_name, salary
    FROM employees;
  r_person c1%ROWTYPE;    
BEGIN
 r_person.first_name := 'John';
 r_person.last_name  := 'Doe';
 r_person.salary     := 2200.00; 
END;

-- rowtype record
DECLARE
  r_person employees%ROWTYPE;    
BEGIN
 r_person.first_name := 'John';
 r_person.last_name  := 'Doe';
 r_person.salary     := 2200.00; 
END;
*/

BEGIN
  EXECUTE IMMEDIATE 'BEGIN logit(:mybindvar, :displaymode);
    END;' USING 'This is my dynamic message.', 'D';
END;


delete t2;
BEGIN
  execute immediate 'insert into t2 (col1, col2) 
    values (:col1val, :col2val)' using 'A', 'B';
  logit('Created Rows: ' || SQL%ROWCOUNT, 'D' );
  
  execute immediate 'update t2 set col1 = :newcol1
    where col2 = :oldcol2' using 'C', 'B';
  logit('Updated Rows: ' || SQL%ROWCOUNT, 'D' );
  
  execute immediate 
  'delete from  t2 where col2 = :oldcol2' using 'B';  
  logit('Deleted Rows: ' || SQL%ROWCOUNT, 'D' );
END;
select * from emp_names_nds;

delete t2;
BEGIN
  t2_dyn_api.insert_row('A', 'B', 1);
  t2_dyn_api.insert_row('D', 'E', 2);
  t2_dyn_api.insert_row('G', 'H', 3);
END;

select * from t2;
BEGIN t2_dyn_api.update_row('X', 'B', 1); END;

select * from t2;
BEGIN t2_dyn_api.delete_row('X', 'B', 1); END;

select * from t2;




DECLARE v_output VARCHAR2(1);
BEGIN
  execute immediate 'insert into t2 (col1, col2) 
    values (:col1val, :col2val) RETURNING col1 INTO :colret'
  using 'A', 'B', OUT v_output;
  logit('v_output: ' || v_output, 'D' );   
END;


DECLARE
  v_output VARCHAR2(1);
BEGIN
  execute immediate 
      'insert into t2 (col1, col2) 
         values (:col1val, :col2val)
         RETURNING col1 INTO :colret'
    using 'A', 'B'
    RETURNING INTO v_output;
  
  logit('v_output: ' || v_output, 'D' );
    
END;


DECLARE
  v_dml_sel VARCHAR2(8000) := '
    SELECT last_name, first_name FROM employees
    WHERE rownum < :rowsproc';
  TYPE r_emp IS RECORD (
    last_name VARCHAR2(25),
    first_name VARCHAR2(20) );
  TYPE v_emp_tbltyp IS TABLE OF r_emp;
  v_emp_tbl v_emp_tbltyp;
BEGIN
  EXECUTE IMMEDIATE v_dml_sel BULK COLLECT INTO v_emp_tbl
  USING 10;

  FORALL ii IN v_emp_tbl.FIRST..v_emp_tbl.LAST
    EXECUTE IMMEDIATE 'INSERT INTO emp_names_nds (last_name, first_name) VALUES (:lastname, :firstname)'
    USING v_emp_tbl(ii).last_name, v_emp_tbl(ii).first_name;
END;

select * from emp_names_nds;
--delete emp_names_nds; -- 99 deleted



-- measure bind performance
declare
  v_char_null varchar2(10);
  v_num_null number;
  v_not_null number := 0;
  v_value number;
  v_loop_cnt PLS_INTEGER := 10000;
  v_start_time timestamp(9);
  v_end_time timestamp(9);
  
  v_rand number := abs(dbms_random.random);

  v_sql_stmt VARCHAR2(1000);  
begin

  v_loop_cnt := v_loop_cnt + v_rand;

  dbms_output.put_line('Random: ' || to_char(v_rand) );
  
  v_start_time := systimestamp;

  FOR i IN v_rand..v_loop_cnt
  LOOP
    v_sql_stmt := 'SELECT NVL(to_number(''''), to_number(''' || i || ''')) FROM DUAL';
    EXECUTE IMMEDIATE v_sql_stmt INTO v_value;
  END LOOP;  
              
  v_end_time := systimestamp;
              
  dbms_output.put_line( 'No Binds, Conversion         ' ||  
              to_char(v_end_time - v_start_time) );

  v_start_time := systimestamp;

  FOR i IN v_rand..v_loop_cnt
  LOOP
    v_sql_stmt := 'SELECT NVL(null, ' || i || ') FROM DUAL';
    EXECUTE IMMEDIATE v_sql_stmt  INTO v_value;
  END LOOP;  
              
  v_end_time := systimestamp;
              
  dbms_output.put_line( 'No Binds, No Conversion      ' ||  
              to_char(v_end_time - v_start_time) );

  v_start_time := systimestamp;

  v_sql_stmt := 'SELECT NVL(:v_num_null, :v_not_null) FROM DUAL' ;
      
  FOR i IN v_rand..v_loop_cnt
  LOOP
    v_not_null := i;
    EXECUTE IMMEDIATE v_sql_stmt  INTO v_value USING IN v_num_null, IN v_not_null;
  END LOOP;  
              
  v_end_time := systimestamp;
              
  dbms_output.put_line( 'Binds, No Conversion         ' ||  
              to_char(v_end_time - v_start_time) );

  v_start_time := systimestamp;

  FOR i IN v_rand..v_loop_cnt
  LOOP
    v_not_null := i;
    SELECT NVL(v_num_null, v_not_null) INTO v_value FROM DUAL;
  END LOOP;  
              
  v_end_time := systimestamp;
              
  dbms_output.put_line( 'Not Dynamic                  ' ||  
              to_char(v_end_time - v_start_time) );

end;






DECLARE
  cursor c_person(c_id in number) is
    SELECT * FROM employees WHERE employee_id = c_id;
  r_person employees%ROWTYPE;    
  v_koef NUMBER;    
  v_upd_employee_id NUMBER;    
  v_cre_employee_id NUMBER;    
BEGIN
  v_koef  := 0.95;
  v_upd_employee_id := 115;
  v_cre_employee_id := 999;
  -- 1. r e a d
  for rx in c_person(v_upd_employee_id) loop
    r_person := rx ;
  end loop ;
                dbms_output.put_line(
                 '--- 1. CRUD R employee_id= '
                 ||v_upd_employee_id||chr(10)
                 ||'r_person.salary='||r_person.salary);
  
  -- 2. u p d a t e
  r_person.salary := r_person.salary * v_koef ;
  UPDATE employees SET salary = r_person.salary 
  WHERE employee_id = r_person.employee_id;
              for rx in c_person(v_upd_employee_id) loop
                r_person := rx ;
              end loop ;
              dbms_output.put_line(
                '--- 2. CRUD U employee_id ='
              ||v_upd_employee_id||chr(10)
              ||'r_person.salary*'||v_koef||'='
              ||r_person.salary
              ||chr(10)
              ||'r_person.LAST_NAME='||r_person.LAST_NAME
              );

  -- 3. d e l e t e
  BEGIN DELETE employees WHERE employee_id = v_cre_employee_id;
  EXCEPTION WHEN others THEN null; END;
               dbms_output.put_line(
 '--- 3. CRUD D (if exists) employee_id='||v_cre_employee_id);

  -- 4. c r e a t e
  r_person.employee_id := v_cre_employee_id;
  r_person.last_name   := 'Doe';
  r_person.first_name  := 'John';
  r_person.email       := '[email protected]';
  INSERT INTO employees VALUES r_person;
              for rx in c_person(v_cre_employee_id) loop
                r_person := rx ;
              end loop ;
               dbms_output.put_line(
               '--- 4. CRUD C employee_id='||v_cre_employee_id
               ||chr(10)
              ||'r_person.salary='||r_person.salary||chr(10)
              ||'r_person.LAST_NAME='||r_person.LAST_NAME
               );

  BEGIN
    --logit;
    BEGIN
      logit('Inserted new employee_id='||v_cre_employee_id);
      DECLARE
        v_a_different_msg VARCHAR2(100);
      BEGIN
        rollback; -- Notice rollback
        v_a_different_msg := 'Inserted new employee_id='||v_cre_employee_id;
        logit( v_a_different_msg );
      END;
    END;
  END;

  --------------- 
END;
/   DECLARE
  v_dml_sel VARCHAR2(8000) := 
    'SELECT * FROM employees WHERE rownum < :rnum1';
  TYPE v_emp_tbltyp IS TABLE OF employees%ROWTYPE;
  v_emp_tbl v_emp_tbltyp;
BEGIN
  EXECUTE IMMEDIATE 
    v_dml_sel BULK COLLECT INTO v_emp_tbl USING 3; --rnum1
  FOR ii IN 1..v_emp_tbl.LAST
  LOOP msg('On Loop: '||ii||', '||v_emp_tbl(ii).last_name);
  END LOOP;     
END;


DECLARE
  v_dml_sel VARCHAR2(8000) := 
  'SELECT first_name, last_name, email, phone_number, hire_date
   FROM employees WHERE employee_id = :p_employee_id';
  r_emp employees%ROWTYPE;
BEGIN
  r_emp.employee_id := 101;
  execute immediate v_dml_sel 
     into r_emp.last_name,
          r_emp.first_name,
          r_emp.email,
          r_emp.phone_number,
          r_emp.hire_date
     using r_emp.employee_id;
    logit(r_emp.last_name||', email='||r_emp.email, 'D');
END;


DECLARE
  v_dml_sel VARCHAR2(8000) := 
  'SELECT first_name, last_name, email, phone_number, hire_date
   FROM employees WHERE employee_id = :p_employee_id';
  --r_emp_refcurs_id NUMBER;
  r_emp_refcurs sys_refcursor;
  r_emp employees%ROWTYPE;
  --v_rows_fetched NUMBER;
BEGIN
  --r_emp_refcurs_id := DBMS_SQL.open_cursor;
  OPEN r_emp_refcurs FOR v_dml_sel USING 101; 
  -- see (1)
  LOOP 
    FETCH r_emp_refcurs INTO 
         r_emp.first_name, 
         r_emp.last_name, 
         r_emp.email, 
         r_emp.phone_number, 
         r_emp.hire_date;
    EXIT WHEN r_emp_refcurs%NOTFOUND; 
    -- see (2)    
  END LOOP; 
    
    --DBMS_SQL.close_cursor(r_emp_refcurs_id);
  CLOSE r_emp_refcurs;
    
    logit(r_emp.last_name||', email='||r_emp.email, 'D');
    
END;

  -- see (1)
  /*
  DBMS_SQL.parse(r_emp_refcurs_id, v_dml_sel, DBMS_SQL.native );
  
  DBMS_SQL.define_column( r_emp_refcurs_id, 1, r_emp.first_name, 20);
  DBMS_SQL.define_column( r_emp_refcurs_id, 2, r_emp.last_name, 25);
  DBMS_SQL.define_column( r_emp_refcurs_id, 3, r_emp.email, 20);
  DBMS_SQL.define_column( r_emp_refcurs_id, 4, r_emp.phone_number, 25);
  DBMS_SQL.define_column( r_emp_refcurs_id, 5, r_emp.hire_date);
  
  DBMS_SQL.bind_variable( r_emp_refcurs_id, 'p_employee_id', 101);
  
  v_rows_fetched := DBMS_SQL.execute(r_emp_refcurs_id);
  */
  -- see (2)
  /*
  IF DBMS_SQL.FETCH_ROWS(r_emp_refcurs_id)> 0 THEN 
    DBMS_SQL.COLUMN_VALUE( r_emp_refcurs_id, 1, r_emp.first_name);
    DBMS_SQL.COLUMN_VALUE( r_emp_refcurs_id, 2, r_emp.last_name);
    DBMS_SQL.COLUMN_VALUE( r_emp_refcurs_id, 3, r_emp.email);
    DBMS_SQL.COLUMN_VALUE( r_emp_refcurs_id, 4, r_emp.phone_number);
    DBMS_SQL.COLUMN_VALUE( r_emp_refcurs_id, 5, r_emp.hire_date);
  ELSE 
    EXIT; 
  END IF;
  */

  
  
set serveroutput oFF

go top

6. Ref Cursor pointer to cursor (ee to record set object variable)

CREATE OR REPLACE PACKAGE PCK_EMPLOYEES IS
--Returned cursor variable of type SYS_REFCURSOR :
-- 1. can be opened for any query 2. it is like view with parameters id, rc...
PROCEDURE getrc_itms_by_mast_id(id IN NUMBER, rc IN OUT SYS_REFCURSOR) ;
--also works FUNCTION getrc_itms_by_mast_id (p_sifra IN NUMBER) RETURN SYS_REFCURSOR ;

PROCEDURE tbl_displ (p_rows IN SYS_REFCURSOR);

END PCK_EMPLOYEES ;
/
sho err

CREATE OR REPLACE PACKAGE BODY PCK_EMPLOYEES IS
PROCEDURE getrc_itms_by_mast_id (id IN NUMBER, rc IN OUT SYS_REFCURSOR) IS
BEGIN
OPEN rc FOR
select * from EMPLOYEES emp where emp.DEPARTMENT_ID = id
order by emp.DEPARTMENT_ID, emp.EMPLOYEE_ID
;
END getrc_itms_by_mast_id;


PROCEDURE tbl_displ(p_rows IN SYS_REFCURSOR) IS
v_row EMPLOYEES%ROWTYPE ;
BEGIN 
dbms_output.put_line('-- ********************** O U T P U T :' );
-- process each row
LOOP
FETCH p_rows INTO v_row ;
EXIT WHEN p_rows%notfound;
dbms_output.put_line('id_dep=' || v_row.DEPARTMENT_ID ||', id_emp=' || v_row.EMPLOYEE_ID);
END LOOP;

CLOSE p_rows;


EXCEPTION 
WHEN OTHERS THEN 
IF p_rows%ISOPEN THEN CLOSE p_rows; END IF; 
RAISE;

END tbl_displ;

END PCK_EMPLOYEES;
/
sho err

--CALL CLS "PCK_EMPLOYEES", METHODS getrc_itms_by_mast_id, tbl_displ
SET SERVEROUTPUT OFF
SET SERVEROUTPUT ON SIZE 1000000 FORMAT WRAPPED
DECLARE
itms_by_mast_id_rc SYS_REFCURSOR ;
BEGIN
PCK_EMPLOYEES.getrc_itms_by_mast_id(30, itms_by_mast_id_rc); --1281, 1282
--itms_by_mast_id_rc := PCK_EMPLOYEES.getrc_itms_by_mast_id (1282); --1281, 1282
PCK_EMPLOYEES.tbl_displ(itms_by_mast_id_rc);
END;
/

-- ********************** O U T P U T :
id_dep=30, id_emp=114
id_dep=30, id_emp=115
id_dep=30, id_emp=116
id_dep=30, id_emp=117
id_dep=30, id_emp=118
id_dep=30, id_emp=119







--NATIVE DYNAMIC SQL – NDS : EXECUTE IMMEDIATE statement example:
CREATE FUNCTION F_row_cnt(tablica_p VARCHAR2) RETURN NUMBER IS 
  naredba VARCHAR2 (1000); 
  broj_redaka NUMBER; 
BEGIN 
  naredba := 'SELECT COUNT (*)' || '  FROM ' || tablica_p; 
  EXECUTE IMMEDIATE naredba INTO broj_redaka; 
  RETURN broj_redaka; 
END; 
/
sho err

SET SERVEROUTPUT OFF
SET SERVEROUTPUT ON SIZE 1000000 FORMAT WRAPPED
exec dbms_output.put_line('-- ********************** O U T P U T :' );
exec dbms_output.put_line('row_cnt emps=' || F_row_cnt('employees'));
-- ********************** O U T P U T :
row_cnt emps=107







SET SERVEROUTPUT OFF
SET SERVEROUTPUT ON SIZE 1000000 FORMAT WRAPPED
-- create dynamic cursor varijable
DECLARE 
  rcdyn SYS_REFCURSOR; 
  stmt_str VARCHAR2(200); 

  LAST_NAME VARCHAR2(100); 
  SALARY NUMBER; 
BEGIN 
  stmt_str := 'SELECT LAST_NAME, SALARY' || ' FROM employees' || ' WHERE JOB_ID = :1' ;
  -- create dynamic cursor varijable :
  dbms_output.put_line('-- ********************** O U T P U T :' );
  OPEN rcdyn FOR stmt_str USING 'SA_MAN';  
  LOOP 
    FETCH rcdyn INTO LAST_NAME, SALARY;
    EXIT WHEN rcdyn%NOTFOUND;  


    --procesiranje podataka
    dbms_output.put_line('LAST_NAME=' || LAST_NAME ||', SALARY=' || SALARY);
  END LOOP;  
  CLOSE rcdyn; 
END; 
/ 

-- ********************** O U T P U T :
LAST_NAME=Russell, SALARY=14000
LAST_NAME=Partners, SALARY=13500
LAST_NAME=Errazuriz, SALARY=12000
LAST_NAME=Cambrault, SALARY=11000
LAST_NAME=Zlotkey, SALARY=10500

1a. Install ZWAMP, Apache, PHP, MySQL, WordPress on Win 10 all 64bit, all portable (extract, setup files)

HOME

22.oct.2016
from  J:\zwamp64\z_apache_php_instalac_doc\z_doc\01_zwamp_instalac_moj.txt

Z-WAMP Server Pack (tools for Apache, PHP web pages developing on all Windows versions 32/64 bit) is a lightweight zero-install Web server package (user GUI).

1. Z-WAMP

is hosted by SourceForge: http://zwamp.sourceforge.net/
download: http://sourceforge.net/projects/zwamp/files/
latest is jan.2013  11_zwamp-x64-2.2.1-full.zip
to DIRECTORY J:\zwamp64\z_apache_php_instalac_doc\win64_x64bit
where is also coresponding MS VC++ which must be installed first (only this one installation) see below vc_redist.x64.
———————————————————-
Latest ZWAMP for Win XP which I have as web site on USB stick – they work on all Windows 32/64 bit versions :
25 MB     11_for_winXP_32bit_zwamp-i386-1.1.2.zip

Last version I extracted php for 32 bit windows xp is 5.4.*  :
11_for_wiXP_32bit_vcredist_x86_VS2008.exe
12_for_winXP_32bit_php-5.4.45-Win32-VC9-x86.zip
Last apache for 32 bit windows xp is 2.4.? or 2.2.? (see apachelounge site)

ZWAMP is Bing Cosca’s project (also author of F3 – Fat free php framework).
Latest ZWAMP 2013 year  for win 10 64 bit contains web development tools:

  1. I use only : Apache, MySQL, PHP, Adminer, – I added phpmyadmin and I extracted their latest versions to Z:\.sys (Z: is for me “J:\zwamp64\vdrive”)
  2. I do not use : MiniPerl 5.14.2, MongoDB 2.2.3,   (PHP 1.3.4 driver),  APC 3.1.13, XCache 3.0.0, XDebug 2.2.1, AdminMongoDB, MemCached, SQLite, eAccelerator, and Alternative PHP Cache (APC)
ZWAMP Version 2.2.1, 2013 year (LATEST RELEASE)
23.oct.2016 I EXTRACTED NEWEST 64 BIT VERSIONS OF  (ALL NO INSTALL, PORTABLE)
Apache 2.4.3 apachelounge
12_apache_httpd-2.4.20-win64-VC14.zip
PHP 5.4.12 12_php-7.0.12-Win32-VC14-x64.zip
MSVC14 (Visual C++ 2015)
MySQL 5.6.10 mysql-5.7.16-winx64.zip,  mysql-5.7.9-winx64.zip
see below EXTRACT PORTABLE: MYSQL
tool
Adminer 3.5.1
Adminer 4.2.5
http://dev1:8083/adminer/adminer.php
see below EXTRACT PORTABLE: MYSQL
ZWAMP does not contain phpMyAdmin phpMyAdmin 4.6.4
see below EXTRACT PORTABLE: MYSQL
ZWAMP does not contain WordPress 1_wordpress-4.6.1.zip   8.5 MB
see below EXTRACT PORTABLE: WORDPRESS

My DIRECTORY J:\zwamp64\z_apache_php_instalac_doc\win64_x64bit
contains :

***** 1. vc_redist (install this first, other SW is portable ): *****
———————————————————-
23.oct.2016 15 MB 10_2015_vc_redist.x64.exe
for .php 7.0.12 64 bit (compiled with Visual Studio 2015)
http://www.microsoft.com/en-us/download/details.aspx?id=48145

—               ***** 2. Apache : *****
—————————————————-
3.jul.2016. 14 MB 12_apache_httpd-2.4.20-win64-VC14.zip
do not forget comment/uncomment:
#LoadModule php5_module /.sys/php/php5apache2_4.dll
LoadModule php7_module /.sys/php/php7apache2_4.dll
in J:\zwamp64\vdrive\.sys\Apache2\conf\httpd.conf
and :

# ZWAMP does:   (subst Z: "J:\zwamp\vdrive")
Listen 8083
# dir J:\zwamp64\vdrive\.sys\php is :
PHPIniDir /.sys/php
# dir J:\zwamp64\vdrive\.sys\php is
<IfModule alias_module>
  # dir. J:\zwamp64\vdrive\.sys\adminer is :
  # http://localhost:8083/adminer/
 Alias /adminer /.sys/adminer
  <Directory /.sys/adminer>
    Options All
    AllowOverride AuthConfig
    Require all granted
  </Directory>

  # http://localhost:8083/phpmyadmin/  
  # WE NEED WAMP WAY for WAMP main menu group 3. Aliases & virt.hosts :
  # J:\zwamp64\vdrive\alias\phpmyadmin.conf for me is all commented
  Alias /phpmyadmin /.sys/phpmyadmin
  <Directory /.sys/phpmyadmin>
    Options All
    AllowOverride AuthConfig
    Require all granted
  </Directory>
</IfModule>

—               ***** 3.1 PHP : *****
————————————————-
http://windows.php.net/download
build date Oct 13 2016 24 MB 12_php-7.0.12-Win32-VC14-x64.zip
oct.2016 23 MB 12_php-5.6.27-Win32-VC11-x64.zip
oct.2015 21 MB 12_php-5.5.38-Win32-VC11-x64.zip
works, oci8 for php7 is supported !!
see trick with php_oci8_11g.dll below

—               ***** 3.2 memcache CURL : *****
—————————————————–
CURL is compiled with php7.0.12,
I do not use memcache (any cache) for now (not needed ?)

—               ***** 4. DB  *****
———————————————————-

—               ***** 4.1 DB sqlite : *****
13.08.2015.  164 kB tema.sqlite
—               ***** 4.2 sqlite develop. tools : *****
24.06.2015.  25 MB 14_sqlitestudio-3.0.6.zip
29.03.2015.  98 kB 14_SQLiteStudio_User Manual.htm

—————————————————-
—         ***** 4.2 DB Oracle 11gXE 64 bit : *****
—————————————————-
332 MB 1_OracleXE112_Win64.zip
see below OracleXE112 INSTALL
see below CONNECT PHP TO OracleXE112
—               ***** Oracle develop. tools : *****
—               Orcle sqldeveloper
—               Orcle sqldeveloper data modeler
—               IDE Netbeans I do not use

—     —————————————————–
—     ***** 4.3 DB mysql (SEE BELOW MYSQL EXTRACT GUIDE) : *****
—     —————————————————–
23.oct.2016.  349 MB 14_mysql-5.7.16-winx64.zip

——————————————————–      —          *****  mysql develop. tools *****
——————————————————-
23.oct.2016.  6 MB  16_phpMyAdmin-4.6.4-all-languages.7z
compatible with PHP 5.5 to 7.0 and MySQL 5.5 and newer.
SHA256: 89ce2055402ea3052d380aebddf3c9c5bfc4ed686f49b98ee2e0f6ec6a3ded6c
old: 16_phpMyAdmin-4.5.0.2-all-languages.7z

23.oct.2016. 283 kB 16_adminer-4.2.5-en.php I renamed to :
J:\zwamp64\vdrive\.sys\adminer\adminer.php
01.06.2016   413 kB adminer-4.2.4.php,  570 kB 16_adminer-master.zip

23.10.2015. 33 MB
15_mysql-workbench-community-6.3.5-winx64-noinstall.zip

2. EXTRACT PORTABLE: MYSQL, PHPMYADMIN, ADMINER

22.oct.2016
http://dev.mysql.com/downloads/mysql/
(phpinfo() shows: mysqli mysqlnd 5.0.12-dev –  20150407 ?)
MD5: 1b23c0ddaa1ad59465fd1702b864e4a3
—–BEGIN PGP SIGNATURE—–  I do not use this
Version: GnuPG v1

iD8DBQBX7U37jHGNO1By4fURAkIGAJ9vU5VfOLHqDnZvvrtq/B/n6jE3MQCgh4C1
9sR5bRIkjwpwJ5Adjekc7uA=
=9Kxd
—–END PGP SIGNATURE—–

348 MB  14_mysql-5.7.16-winx64.zip
36 MB   14_mysql_refman-5.7.16-en.a4.pdf
http://dev.mysql.com/doc/refman/5.7/en/  http://dev.mysql.com/doc/

A bit more difficult for beginner user is to integrate newest
Apache. php, mysql, phpmyadmin, adminer in ZWAMP
(all portable = extract  & setup & run).

Testing MySQL is best in console (command prompt) window – best mysql msgs.
I did not use MSI mysql installer (is it better ?)
======================================================

If using no install mysql zip, you need to:

1. ***EXTRACT MYSQL***
unzip  J:\zwamp64\z_apache_php_instalac_doc\win64_x64bit\14_mysql-5.7.16-winx64.zip
to ZWAMP dir:  J:\zwamp64\vdrive\.sys\mysql (rename old to mysql_5_7_9)

2. Create ***OPTIONS*** file my.ini – see my.ini below
or copy my.ini from mysql_5_7_9 dir to mysql dir
Optional I id not:   extract the debug-test archive if you plan to execute the MySQL benchmark and test suite

???I DID NOT: Choose a MySQL ***SERVER TYPE***, it could be :
it is server-id    = 1 ???
– mysqld Optimized binary with named-pipe support
– or mysqld-debug – like mysqld, but compiled with
full debugging and automatic memory allocation checking

3. ***INITIALIZE MYSQL***
3.1 Freecommander in admin mode and click CLI icon
or (I did):
make icon C:\Windows\SysWOW64\cmd.exe -> right click -> run as admin
J:
cd J:\zwamp64\vdrive\.sys\mysql

3.2   .\bin\mysqld –initialize-insecure –user=mysql

MySQL ee mysqld creates dir :
J:\zwamp\vdrive\.sys\mysql\data – we can move it if needed

data dir we can delete to try –initialize-insecure again if
installation was unsuccesfull as my was first time I used
–initialize mysqld parameter
I did not know how resolve errors – same as MANY PEOPLE ON WEB FORUMS :
‘Access denied for user ‘root’@’localhost’
or
‘Your password has expired

4. ***START*** MySQL server :
4.1 First this to be able to do 4.2 !! :
Establish ZWAMP try icon & start Apache and mysql
(or 2click on: J:\zwamp64\zwamp.exe)
Rightclick on ZWAMP try icon
– standard ZWAMP, WAMP or XAMPP functions.

ZWAMP Services menu item should show apache and mysql started.

4.2 Execute mysql.exe to ***OPEN MYSQL CONNection***
to open mysql prompt:
J:
cd J:\zwamp\vdrive\.sys\mysql

.\bin\mysql -u root -p 
Enter password: *****
press ENTER key if you not yet have root psw *****
then ***GIVE PASSWORD TO ROOT USER***
ALTER USER ‘root’@’localhost’ IDENTIFIED BY ‘root’;
         exit
So we avoided error:
ERROR 1045 (28000): Access denied for user ‘root’@’localhost’ (using password: YES)

Then again :
.\bin\mysql -u root -p

or .\bin\mysql -u root -h 127.0.0.1 –skip-password

If we try 4.2 without ZWAMP started (5.1) :
Enter password: ****
ERROR 2003 (HY000): Cant connect to MySQL server on ‘localhost’ (10061)

Why we need password :
– secure default user accounts
– Portable phpMyAdmin says “Login without psw is forbidden by configuration”

5. MYSQL TOOLS

http://dev1:8083/phpmyadmin – login into mysql with portable phpMyAdmin works after :
rename J:\zwamp64\vdrive\.sys\phpMyAdmin to phpMyAdmin_4_5_0_2
16_phpMyAdmin-4.6.4-all-languages.7z  6 MB ***phpMyAdmin EXTRACT*** to :
J:\zwamp64\vdrive\.sys\phpMyAdmin
copy J:\zwamp64\vdrive\.sys\phpMyAdmin_4_5_0_2\config.inc.php
to J:\zwamp64\vdrive\.sys\phpMyAdmin\config.inc.php
see below config.inc.php

http://dev1:8083/adminer/adminer.php — login into mysql with portable adminer works
— login into oracle 11gXE with portable adminer works
16_adminer-4.2.5-en.php 283 kB copyed to adminer dir
same as phpMyAdmin and renamed to adminer.php, no setup file changes required

http://dev1:8083/adminer/ed/editor.php — is only for mysql DB

http://dev1:8083/adminer/ed/oraed.php — is only for Oracle DB

ˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇ end mysql 64 bit installation

http://dev1:8083/phpmyadmin displays:

Database server
Server: localhost via TCP/IP
Server type: MySQL
Server version: 5.7.16 – MySQL Community Server (GPL)
Protocol version: 10
User: root@localhost
Server charset: UTF-8 Unicode (utf8)

Web server
Apache/2.4.20 (Win64)
Database client version: libmysql – mysqlnd 5.0.12-dev – 20150407 – $Id: 241ae00989d1995ffcbbf63d579943635faf9972 $
PHP extension: mysqliDocumentation curlDocumentation mbstringDocumentation
PHP version: 7.0.12

phpMyAdmin
Version information: 4.6.4 (up to date)
Documentation
Official Homepage
Contribute
Get support
List of changes
License

Starting MySQL from the Windows Command Line
=======================================
mysqld — corresponds to Oracle DB server daemon(TSR) service name (XE)

Stop MySQL server by executing this command:
mysqladmin -u root -p shutdown

Start mysqld with the –standalone and –debug options. In debug case, mysqld writes a log file C:\mysqld.trace that should contain the reason WHY MYSQLD DOESNT START. See Section 24.5.3, “The DBUG Package”.
Use mysqld –verbose –help to display all the options that mysqld supports.

2.3.5.6 Customizing the PATH for MySQL Tools
============================================
To make it easier to invoke MySQL programs, you can add the path name of the MySQL bin directory to your Windows system PATH environment variable.
You should not add the MySQL bin directory to your Windows PATH if you are running multiple MySQL servers on the same machine.

https://www.adminer.org/#download
Adminer – Database management in a single PHP file
Adminer Editor – Data manipulation for end-users

https://www.adminer.org/
Supports: MySQL, PostgreSQL, SQLite, MS SQL, Oracle, SimpleDB, Elasticsearch
Requirements: PHP 5+
Apache License 2.0 or GPL 2

To see what databases (users in Oracle DB terminology) exist :
————————————————-
(in oracle DB user coresponds to mysql DB)
goto J:\zwamp64\vdrive\.sys\mysql\bin

mysqld –help
mysqld  Ver 5.7.16 for Win64 on x86_64 (MySQL Community Server (GPL))
Copyright (c) 2000, 2016, Oracle and/or its affiliates.
Starts the MySQL database server.

Usage: mysqld [OPTIONS]

For more help options (several pages), use
mysqld –verbose –help

mysqlshow -u root -p
+——————–+
|     Databases      |
+——————–+
| information_schema |
| blogwp             |
| mysql              |
| performance_schema |
| sys                |
+——————–+
Two DB ar minimum.

mysqlshow -u root mysql
Database: mysql
+—————————+
|          Tables           |
+—————————+
| columns_priv              |
| db                        |

+—————————+

To select information from a table in the mysql database :
mysql -e “SELECT User, Host, plugin FROM mysql.user” -u root mysql
+———–+———–+———————–+
| User      | Host      | plugin                |
+———–+———–+———————–+
| root      | localhost | mysql_native_password |
| mysql.sys | localhost | mysql_native_password |
+———–+———–+———————–+

mysqladmin -u root version status proc
mysqladmin  Ver 8.42 Distrib 5.7.16, for Win64 on x86_64
Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
Server version          5.7.16
Protocol version        10
Connection              localhost via TCP/IP
TCP port                3306
Uptime:                 41 min 55 sec

Threads: 1  Questions: 21  Slow queries: 0  Opens: 115  Flush tables: 1  Open tables: 0  Queries per second avg: 0.008
Uptime: 2515  Threads: 1  Questions: 22  Slow queries: 0  Opens: 115  Flush tables: 1  Open tables: 0  Queries per second avg: 0.008
+—-+——+—————–+—-+———+——+———-+——————+
| Id | User | Host            | db | Command | Time | State    | Info             |
+—-+——+—————–+—-+———+——+———-+——————+
| 11 | root | localhost:50191 |    | Query   | 0    | starting | show processlist |
+—-+——+—————–+—-+———+——+———-+——————+

To display all the options that mysqld supports:
.\bin\mysqld –verbose –help

J:\zwamp\vdrive\.sys\mysql>.\bin\mysql -u root -p
Enter password:
mysql> SELECT User, Host, Password FROM mysql.user;
ERROR 1054 (42S22): Unknown column ‘Password’ in ‘field list’
mysql> SELECT User, Host FROM mysql.user;
+———–+———–+
| User      | Host      |
+———–+———–+
| mysql.sys | localhost |
| root      | localhost |
+———–+———–+
2 rows in set (0.00 sec)

# ————————————-
# my.ini     mysql 5.7.16 config file
# ————————————-
# J:\zwamp64\vdrive\.sys\mysql\my.ini
[client]
password    = root
port          = 3306
socket        = /.tmp/mysql.sock

[mysqld]
basedir = J:/zwamp64/vdrive/.sys/mysql
datadir = J:/zwamp64/vdrive/.sys/mysql/data
# default IPv6 change to ipv4
bind-address = 0.0.0.0
skip-external-locking
key_buffer_size = 16K
max_allowed_packet = 1M
table_open_cache = 4
sort_buffer_size = 64K
read_buffer_size = 256K
read_rnd_buffer_size = 256K
net_buffer_length = 2K
thread_stack = 128K
sync_binlog = 0
explicit_defaults_for_timestamp = TRUE
server-id    = 1

sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES

[mysqldump]
quick
max_allowed_packet = 16M

[mysql]
no-auto-rehash
# Remove the next comment character if you are not familiar with SQL
safe-updates

[myisamchk]
key_buffer_size = 8M
sort_buffer_size = 8M

[mysqlhotcopy]
interactive-timeout

# ————————————-
# config.inc.php   phpMyAdmin 4.6.4 config file
# ————————————-
// J:\zwamp64\vdrive\.sys\phpMyAdmin\config.inc.php
$cfg[‘blowfish_secret’] = ”; /* YOU MUST FILL IN THIS FOR COOKIE AUTH! */
$i = 0;
$i++;
/* Authentication type */
//$cfg[‘Servers’][$i][‘auth_type’] = ‘cookie’;
//  if you prefer to not be prompted every time you log in:
$cfg[‘Servers’][$i][‘user’]          = ‘root’;
$cfg[‘Servers’][$i][‘password’]      = ‘root’; // use here your password
//$cfg[‘Servers’][$i][‘auth_type’]     = ‘config’;
/* Server parameters */
$cfg[‘Servers’][$i][‘host’] = ‘localhost’;
$cfg[‘Servers’][$i][‘connect_type’] = ‘tcp’;
$cfg[‘Servers’][$i][‘compress’] = false;
$cfg[‘Servers’][$i][‘AllowNoPassword’] = false;

$cfg[‘UploadDir’] = ”;
$cfg[‘SaveDir’] = ”;

3.  EXTRACT PORTABLE: WORDPRESS

http://sspc1:8083/papl1/blogwp/wp-admin/  = Control panel (Ndzorna ploča)
http://sspc1:8083/papl1/blogwp/  = articles, posts, članci, objave

http://sspc1:8083/papl1/blogwp/primjer-stranice/ = page

http://sspc1:8083/papl1/blogwp/2016/10/22/dan-svijete/

http://sspc1:8083/papl1/blogwp/wp-admin/about.php

https://wordpress.org/download/
http://codex.wordpress.org/Installing_WordPress

1. extract 1_wordpress-4.6.1.zip, 8.5 MB
to
J:\zwamp64\vdrive\web\papl1\blogwp

2. 5-Minute Installation
————————

11111 start apache & mysql

start ZWAMP
rightclick ZWAMP icon and check services apache and mysql are running

22222 create mysql DB and user for WordPress blog

z:
dir .sys
cd .sys\mysql\bin
mysqlshow -u root -p
mysql -u root -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.7.16 MySQL Community Server (GPL)
Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
Type ‘help;’ or ‘\h’ for help. Type ‘\c’ to clear the current input statement.

1.        mysql> DROP DATABASE blogwp; (possible repeat this)
1.        mysql> CREATE DATABASE blogwp;
2.cre usr mysql> GRANT ALL PRIVILEGES ON blogwp.* TO “blogwp”@”localhost”
-> IDENTIFIED BY “blogwp”;
3. mysql>        FLUSH PRIVILEGES;
4. mysql>        EXIT

or in GraphicUI which creates statements below :

http://dev1:8083/phpmyadmin/
create db blogwp collation utf8_… ,:
New link on left top

CREATE USER ‘blogwp’@’%’ IDENTIFIED WITH mysql_native_password BY ‘***’;
GRANT ALL PRIVILEGES ON *.* TO ‘blogwp’@’%’ REQUIRE NONE WITH GRANT OPTION MAX_QUERIES_PER_HOUR 0 MAX_CONNECTIONS_PER_HOUR 0 MAX_UPDATES_PER_HOUR 0 MAX_USER_CONNECTIONS 0;
GRANT ALL PRIVILEGES ON `blogwp`.* TO ‘blogwp’@’%’;
REVOKE ALL PRIVILEGES ON `blogwp`.* FROM ‘blogwp’@’%’;
GRANT ALL PRIVILEGES ON `blogwp`.* TO ‘blogwp’@’%’ WITH GRANT OPTION;

33333 install WordPress blog tables to MySQL DB

http://sspc1:8083/papl1/blogwp/
or http://sspc1:8083/papl1/blogwp/wp-admin/install.php
Needed info about DB:
DB name               blogwp
DB user name          blogwp
DB psw                blogwp
Host of DB            localhost  or PC name eg SSPC1 or domain name eg http://www.mysite.hr
tables Prefiks        blogwp
(if we want more WordPress installations in one DB)

Above info is used to create wp-config.php file. Also you can edit
wp-config-sample.php. See https://codex.wordpress.org/Editing_wp-config.php

psw=…  email=…

Akismet blog spam protection needs :
email,  usr/psw, API key
https://akismet.com/account/

http://sspc1:8083/papl1/blogwp/  = articles, posts, članci, objave
http://sspc1:8083/papl1/blogwp/wp-admin/  = control panel

44444  WordPress Importer

will import the following content from a WordPress export file:
posts, pages, comments, categories, and other content.
<!–J:\zwamp64\vdrive\web\papl1\blogwp\1_phporacle.wordpress.2016-10-22.xml
This is a WordPress eXtended RSS file (WXR) generated by WordPress as an export of your site.
–>
<!– You may use this file to TRANSFER CONTENT FROM ONE SITE TO ANOTHER. –>
<!– This file is not complete backup of your site. –>

<!– TO IMPORT THIS INFORMATION INTO A WORDPRESS SITE : –>
<!– 1. Log in to that site as an administrator. –>
<!– 2. Go to TOOLS: IMPORT IN THE WORDPRESS ADMIN PANEL. –>
<!– 3. Install the “WordPress” importer from the list. –>
<!– 4. Activate & Run Importer. –>
<!– 5. Upload this file using the form provided on that page. –>
<!– 6. You will first be asked to MAP THE AUTHORS IN THIS EXPORT FILE TO USERS –>
<!–    on the site. For each author, you may choose to map to an –>
<!–    existing user on the site or to create a new user. –>
<!– 7. WORDPRESS WILL THEN IMPORT each of the posts, pages, comments, categories, etc. contained in this file into your site. –>
<!– generator=”WordPress/4.6.1″ created=”2016-10-22 12:46″ –>

If you would prefer to do things manually then follow these instructions:
Upload the wordpress-importer folder to the /wp-content/plugins/ directory
Activate the plugin through the ‘Plugins’ menu in WordPress
Go to the Tools -> Import screen, click on WordPress

Remember to update the passwords and roles of imported users.

Many web hosts now offer tools (e.g. Fantastico) to automatically install WordPress for you.
WordPress  has Automatic upgrading.

Things to Know/todo Before You Begin Installing WordPress
————————————————
– Access to web server (via FTP or shell)
– text editor
– FTP Client
– Web browser (K-meleon, Firefox, Google Chrome)

Minimum requirements to run WordPress:
– PHP version 5.6 or greater
– MySQL version 5.6 or greater OR . – MariaDB version 10.0 or greater -http://dev1:8083/phpmyadmin/
WordPress also works with PHP 5.2.4+ and MySQL 5.0+, but these versions have reached official End Of Life and as such may expose your site to security vulnerabilities.

******************************************************
OracleXE112 INSTALL
******************************************************
see my other article or just install it as any Windows program.

4. CONNECT PHP 7.0.12  TO Oracle 11g r2 XE

Oracle instantclient is not needed if all is on home development PC :
OCI8 Extension – WORKS FOR PHP 7.0.12 64 BIT build date Oct 13 2016

Use php 7.0.12 OCI8 extension to access Oracle Database 11g XE from PHP

I did for php 7.0.12, 64 bit:
———————-
download: https://pecl.php.net/package/oci8
https://pecl.php.net/package/oci8/2.1.2/windows
7.0 Thread Safe (TS) x64
TRICK: from J:\zwamp64\vdrive\.sys\php\ext\1_php_oci8-2.1.2-7.0-ts-vc14-x64.zip   20.sep.2016 734 kB
extract php_oci8_11g.dll in J:\zwamp64\vdrive\.sys\php\ext

I also installed  php 5.6.27, 64 bit:
—————————–
I renamed php dir to php_7_0_12
I renamed php_5_6_27 dir to php
download: https://pecl.php.net/package/oci8/2.0.12/windows
5.6 Thread Safe (TS) x64
from J:\zwamp64\vdrive\.sys\php\ext\1_php_oci8-2.0.12-5.6-ts-vc11-x64.zip     20.sep.2016 581 kB
extract php_oci8_11g.dll in J:\zwamp64\vdrive\.sys\php\ext

OCI8 php extension needs to be linked with Oracle 12, 11, or 10.2
client libraries.  These libraries are found in your database installation,
or (I did not this) :   in the free Oracle Instant Client from
http://www.oracle.com/technetwork/database/features/instant-client/
Install the ‘Basic’ or ‘Basic Lite’ Instant Client package.  If
building from source, then also install the SDK package.
aug.2015.  55 MB 18_instantclient-basic-windows.x64-11.2.0.4.0.zip
nov.2014.  73 MB instantclient-basic-windows.x64-12.1.0.2.0.zip

Oracle standard cross-version connectivity applies.  For example,
PHP OCI8 linked with Instant Client 11.2 can connect to Oracle
Database 9.2 onward.  See Oracle note “Oracle Client / Server
Interoperability Support” (ID 207303.1) for details.

see README of pecl oci8 dll-s zip above
see Documentation is at http://php.net/oci8